Sass selector.unify()

Beginner
8 min read
Updated: Nov 2026
5 examples
Dart Sass 1.23+

Definition and Usage

selector.unify($selector1, $selector2) returns a selector that matches only elements matched by both arguments—or null if there is no expressible overlap. Load with @use "sass:selector".

Official sample idea.

unify("a", ".disabled") → a.disabled; unify("a", "h1") → null; complex pairs can expand into a list.

Guard null.

Store the result and check with @if $u before interpolating it as a CSS selector.

Complex caveat.

Like @extend, when both sides are complex the result is not guaranteed to cover every possible shared element. Need a coverage boolean instead? Use is-superselector().

Syntax

SCSS
@use "sass:selector";

selector.unify($selector1, $selector2) //=> selector | null

selector.unify("a", ".disabled"); // a.disabled
selector.unify("a.disabled", "a.outgoing"); // a.disabled.outgoing
selector.unify("a", "h1"); // null
selector.unify(".warning a", "main a");
// .warning main a, main .warning a

// Safe use:
$u: selector.unify($a, $b);
@if $u {
  #{$u} { ... }
}

// Global alias (legacy): selector-unify($selector1, $selector2)
// Prefer selector.unify after @use "sass:selector"

Pattern: pass two selectors → get overlap or null → guard before emitting CSS.

Overlap vs Coverage

Related helpers, different answers:

HelperReturnsUse when
selector.unifyOverlap selector or nullYou need a selector for the intersection
selector.is-superselectortrue / falseYou only need to know if one covers the other

SCSS Examples

Examples use @use "sass:selector". Open View Compiled CSS for verified Dart Sass output (matches official Sass docs samples where shown).

Example 1 — Official Unify Samples

Compounds, merged classes, null, and complex pairs.

SCSS
@use "sass:meta";
@use "sass:selector";

.probe {
  --compound: #{selector.unify("a", ".disabled")};
  --merge: #{selector.unify("a.disabled", "a.outgoing")};
  --null: #{meta.inspect(selector.unify("a", "h1"))};
  --complex: #{selector.unify(".warning a", "main a")};
}

How It Works

  1. Compatible type + class unify into a compound.
  2. Shared type merges extra classes.
  3. Incompatible types return null.
  4. Complex pairs can expand into multiple forms.

Example 2 — Build Rule Selectors

Interpolate a successful unify result into a style rule.

SCSS
@use "sass:selector";

#{selector.unify(".btn", ".primary")} {
  background: teal;
}

How It Works

  1. Two classes unify into one compound.
  2. #{…} turns the result into a CSS rule.
  3. Only safe when you know the result is not null.
  4. Prefer a guard in reusable mixins.

Example 3 — Guard Against Null

Only emit a rule when unify succeeds.

SCSS
@use "sass:selector";

@mixin both($a, $b) {
  $u: selector.unify($a, $b);
  @if $u {
    #{$u} {
      outline: 2px solid currentColor;
    }
  }
}

@include both("a", ".disabled");
@include both("a", "h1");

How It Works

  1. First include unifies successfully.
  2. Second include returns null.
  3. @if $u skips the null case.
  4. Safe default for mixin APIs.

Example 4 — Unify vs Superselector

Overlap selector vs coverage boolean.

SCSS
@use "sass:selector";

.compare {
  --unify: #{selector.unify(".warning a", "main a")};
  --is-super: #{selector.is-superselector("a", ".warning a")};
}

How It Works

  1. unify builds an overlap selector list.
  2. is-superselector only answers coverage.
  3. Different tools for different questions.
  4. Choose unify when you need a selector value.

Example 5 — Batch Try Unify

Emit success and failure markers for several pairs.

SCSS
@use "sass:selector";

@mixin try-unify($name, $a, $b) {
  $u: selector.unify($a, $b);
  @if $u {
    .ok-#{$name} {
      content: "#{$u}";
    }
  } @else {
    .no-#{$name} {
      content: "null";
    }
  }
}

@include try-unify("link", "a", ".link");
@include try-unify("featured", ".card", ".featured");
@include try-unify("lists", "ul", "ol");

How It Works

  1. Compatible pairs unify into compounds.
  2. ul + ol cannot share an element type.
  3. @else records the null path.
  4. Useful for probing design-system selectors.

Edge Cases & Pitfalls

Most unify bugs are interpolating null or expecting perfect complex coverage.

null

Always guard the result

Use @if $u before #{$u} as a selector.

types

Different elements = null

a and h1 cannot unify; neither can ul and ol.

complex

Complex pairs may expand

You can get a list of unified forms—and coverage may not be exhaustive.

inspect

Print null with meta.inspect

Direct #{} of null is awkward; use meta.inspect.

Sass Support

Prefer the module form with current Dart Sass.

APIStatus
selector.unify()Dart Sass 1.23+ via @use "sass:selector"
Return typeSelector or null
Complex pairsMay return a selector list
Legacy globalselector-unify($selector1, $selector2)

Compile with the Dart Sass CLI.

Key Takeaways

  • Returns the overlap of two selectors, or null.
  • Guard with @if before interpolating as a CSS selector.
  • vs is-superselector — that one returns a boolean only.
  • Prefer @use "sass:selector" (Dart Sass 1.23+).

One line: to get a selector for the overlap of two selectors, use selector.unify($selector1, $selector2).

Compile Notes

Practical checklist:

checklist.txt
1. @use "sass:selector"
2. Pass two selectors to unify
3. Store the result in a variable
4. Guard with @if before #{$u}
5. Use is-superselector when you only need true/false

Frequently Asked Questions

selector.unify($selector1, $selector2) returns a selector that matches only elements matched by both selectors. Example: unify("a", ".disabled") becomes a.disabled.
It returns null if the two selectors do not match any of the same elements, or if there is no selector that can express their overlap. Example: unify("a", "h1") is null.
Complex pairs can produce a list of unified forms. Example: unify(".warning a", "main a") becomes .warning main a, main .warning a. The result is not guaranteed to cover every possible shared element when both sides are complex.
Yes. selector-unify($selector1, $selector2) is the legacy global name. Prefer selector.unify after @use "sass:selector".
Store the result in a variable and guard with @if $u { ... } before interpolating it as a selector.
Dart Sass 1.23+. LibSass and Ruby Sass do not load sass:selector with @use; they may still offer the legacy global name.

Next: Sass string.index()

Start the string module—find where a substring begins.

string.index() →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful