Sass selector.unify() Function

Intermediate
⏱️ 12 min read
📚 Updated: Jul 2026
🎯 5 Examples
sass:selector · Dart Sass 1.23+

What You’ll Learn

selector.unify() belongs to the built-in sass:selector module. It builds a selector that matches only elements matched by both inputs—or returns null when there is no expressible overlap. This page covers compounds, complex pairs, safe @if guards, and five compiled examples.

01

Concept

Selector overlap

02

Module

@use "sass:selector"

03

Returns

Selector or null

04

Args

$selector1, $selector2

05

Null

Guard with @if

06

Practice

5 examples

What Is selector.unify()?

Official docs: returns a selector that matches only elements matched by both $selector1 and $selector2. If the selectors do not overlap, or if Sass cannot express that overlap as a selector, the result is null.

  • Simple compounds often merge: a + .disableda.disabled.
  • Incompatible types return null: a + h1.
  • Complex pairs can expand into multiple forms (similar ideas to @extend unification).
  • Official caveat: when both sides are complex, the result is not guaranteed to match every element matched by both.
💡
Beginner tip

Think Venn diagram: unify keeps the overlap. a and .disabled share a.disabled. a and h1 share nothing you can write as one element selector, so you get null.

📝 Syntax

styles.scss
@use "sass:selector";

// Recommended
selector.unify($selector1, $selector2)

// Legacy global name
selector-unify($selector1, $selector2)

Parameters

ParameterTypeRequiredDescription
$selector1SelectorYesFirst selector to unify.
$selector2SelectorYesSecond selector to unify.

Return value

TypeResult
SelectorA selector matching the overlap of both inputs
nullNo expressible overlap

📦 Loading sass:selector

styles.scss
// Recommended — namespaced (Dart Sass 1.23+)
@use "sass:selector";
$u: selector.unify("a", ".disabled"); // a.disabled

// Optional — bring members into scope
@use "sass:selector" as *;
$u: unify("a", ".disabled");

// Legacy global
$u: selector-unify("a", ".disabled");

🎨 Official Patterns

CallResult
unify("a", ".disabled")a.disabled
unify("a.disabled", "a.outgoing")a.disabled.outgoing
unify("a", "h1")null
unify(".warning a", "main a").warning main a, main .warning a

The last sample shows why complex unification can emit a comma list: ancestor order can vary, so Sass lists the sensible combinations.

⚖️ unify vs is-superselector

HelperQuestion it answersTypical result
selector.unifyWhat selector matches both?Selector or null
selector.is-superselectorDoes A cover everything B matches?true / false

🛠 Compatibility

This is about Sass compilers, not browsers. Unification runs at compile time.

Implementationunify
Dart SassYes — prefer selector.unify (module since 1.23.0)
LibSassLegacy selector-unify may exist; no @use "sass:selector"
Ruby SassLegacy selector-unify may exist; no @use "sass:selector"

Prefer current Dart Sass so the module API matches the official docs.

⚡ Quick Reference

GoalCode
Import selector@use "sass:selector";
Merge compoundsselector.unify("a", ".disabled")
Check for null$u: selector.unify(…); @if $u { … }
Print null safelymeta.inspect(selector.unify("a", "h1"))
Use as a selector#{$u} { … } after an @if guard

Examples Gallery

Each example uses selector.unify at compile time (Dart Sass 1.23+). Open View Compiled CSS for verified output.

📚 Getting Started

Official docs samples, then real CSS rules.

Example 1 — Official Unify Samples

Compounds, merged classes, null, and complex pairs.

styles.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

Use meta.inspect when printing null into CSS custom properties. Successful unifications interpolate as normal selector text.

Example 2 — Build Rule Selectors

Interpolate a successful unify result into a style rule.

styles.scss
@use "sass:selector";

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

How It Works

Two class selectors unify into one compound. Only do this when you know the result is not null.

📈 Practical Patterns

Null guards, comparisons, and batch tries.

Example 3 — Guard Against Null

Only emit a rule when unify succeeds.

styles.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

The second include returns null, so no CSS is emitted. That pattern is the safe default for mixin APIs.

Example 4 — Unify vs Superselector

Overlap selector vs coverage boolean.

styles.scss
@use "sass:selector";

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

How It Works

unify builds an overlap selector list. is-superselector only answers whether a covers .warning a.

Example 5 — Batch Try Unify

Emit success and failure markers for several pairs.

styles.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

Compatible class/type pairs unify. Two different element types (ul / ol) cannot share one element, so the result is null.

🚀 Real-World Use Cases

  • Mixin APIs — combine a base selector with a modifier only when valid.
  • Design-system guards — skip impossible pairs instead of emitting broken CSS.
  • Compound builders — merge tag + class or class + class into one selector.
  • Complex layout tooling — unify nested contexts like warning/main links.
  • Debugging — print overlaps with meta.inspect, including null.

🧠 How Compilation Works

1

Pass two selectors

Call selector.unify($selector1, $selector2).

Source
2

Sass finds the overlap

Merges compounds or expands complex pairs—or returns null.

Compile
3

Guard, then interpolate

Use @if $u before #{$u} { … }.

Emit
4

CSS ships

Browsers only see finished selectors like a.disabled—never null.

⚠️ Common Pitfalls

  • Interpolating null — always guard with @if or print via meta.inspect.
  • Assuming full coverage for complex pairs — official docs warn the result may not match every shared element.
  • Confusing with append — append glues strings; unify computes overlap.
  • Confusing with is-superselector — that returns a boolean, not a selector.
  • Old compilers without modules — use Dart Sass 1.23+ for @use "sass:selector".

💡 Best Practices

✅ Do

  • Use @use "sass:selector" and selector.unify()
  • Store the result and check with @if $u
  • Use it to merge compatible compounds safely
  • Prefer is-superselector when you only need a yes/no
  • Prefer Dart Sass 1.23+

❌ Don’t

  • Interpolate a unify result without a null check
  • Assume every pair must succeed
  • Treat complex unify as a perfect set intersection
  • Expect browsers to evaluate the call
  • Rely on LibSass for the module API

Key Takeaways

Knowledge Unlocked

Five things to remember about selector.unify()

Build the overlap of two selectors—or get null when there is none.

5
Core concepts
📦 02

Module

sass:selector

@use
🔗 03

Result

selector or null

Output
📚 04

Complex

may expand lists

Detail
05

Safety

@if before emit

Guard

❓ 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.
Official docs: 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.
Did you know?

Official Sass docs note that unify results for complex selectors are related to @extend unification—so you may get more than one complex selector in the returned list.

Conclusion

selector.unify() builds the overlap of two selectors, or returns null when there is no expressible match. Guard with @if before emitting rules, and remember complex pairs can expand into multiple selectors.

Continue with string.index() or the Sass introduction.

Next: find substrings

Learn string.index() to find the first index of a substring.

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.

5 people found this page helpful