selector.extend() belongs to the built-in sass:selector module. It rewrites a selector the same way the @extend rule would—keeping the original and adding extended forms. This page covers the three arguments, vs selector.replace, and five compiled examples.
01
Concept
@extend as a function
02
Module
@use "sass:selector"
03
Returns
Selector value
04
Args
selector, extendee, extender
05
vs replace
Keep vs swap
06
Practice
5 examples
Concept
What Is selector.extend()?
Official docs: extends $selector as with the @extend rule. It returns a copy of $selector modified as if this ran:
styles.scss
#{$extender} {
@extend #{$extendee};
}
In plain terms: wherever $extendee appears in $selector, Sass keeps that match and adds forms that use $extender instead. If $selector never contains $extendee, the value is returned unchanged.
Three arguments: the selector to rewrite, what to extend from, and what extends it.
Placeholder selectors are allowed; parent selectors (&) are not.
See also selector.replace() when you want a swap instead of an add-on.
💡
Beginner tip
Think of sharing styles: a.disabled extended by .link becomes a.disabled, .disabled.link—both keep the .disabled piece.
Foundation
📝 Syntax
styles.scss
@use "sass:selector";
// Recommended
selector.extend($selector, $extendee, $extender)
// Legacy global name
selector-extend($selector, $extendee, $extender)
Parameters
Parameter
Type
Required
Description
$selector
Selector
Yes
Selector to rewrite with @extend-style unification.
$extendee
Selector
Yes
The piece being extended (what @extend would target).
$extender
Selector
Yes
The selector that extends $extendee.
Return value
Type
Result
Selector
Extended selector list (or the original if $extendee was absent)
Modules
📦 Loading sass:selector
styles.scss
// Recommended — namespaced (Dart Sass 1.23+)
@use "sass:selector";
$sel: selector.extend("a.disabled", "a", ".link");
// a.disabled, .disabled.link
// Optional — bring members into scope
@use "sass:selector" as *;
$sel: extend("a.disabled", "a", ".link");
// Legacy global
$sel: selector-extend("a.disabled", "a", ".link");
The third sample shows intelligent unification: complex extenders can produce more than one new complex selector, not just a simple class swap. Dart Sass may print compound classes in a different simple-selector order (for example .disabled.link); matching is the same.
Compare
⚖️ extend vs replace
Helper
Typical result for a.disabled / a → .link
Use when
selector.extend
a.disabled, .disabled.link
Keep the original and add the extender form
selector.replace
.disabled.link
Swap the original piece out completely
Support
🛠 Compatibility
This is about Sass compilers, not browsers. The rewrite runs at compile time.
Implementation
extend
Dart Sass
Yes — prefer selector.extend (module since 1.23.0)
LibSass
Legacy selector-extend may exist; no @use "sass:selector"
Ruby Sass
Legacy selector-extend may exist; no @use "sass:selector"
Prefer current Dart Sass so the module API matches the official docs.
Keeps $extendee matches and adds unified $extender forms.
Compile
3
Interpolate into rules
Use #{…} as the selector for a style block.
Emit
4
✓
CSS ships
Browsers only see finished lists like a.disabled, .disabled.link.
Watch Out
⚠️ Common Pitfalls
Confusing with replace — extend keeps the original; replace swaps it out.
Parent selectors — & is not allowed in these arguments.
Wrong argument order — remember selector, then extendee, then extender.
Forgetting interpolation — wrap results in #{…} to use them as rule selectors.
Expecting CSS @extend — this is a Sass function result, not a browser feature.
Pro Tips
💡 Best Practices
✅ Do
Use @use "sass:selector" and selector.extend()
Use it when you want to keep the original selector
Prefer replace when a full swap is clearer
Pass clean selectors without parent &
Prefer Dart Sass 1.23+
❌ Don’t
Pass parent selectors (&)
Assume every miss is an error—unchanged return is intentional
Confuse this function with the @extend at-rule syntax alone
Expect browsers to evaluate the call
Rely on LibSass for the module API
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about selector.extend()
Rewrite selectors with @extend logic—keep the original and add extender forms.
5
Core concepts
📝01
API
extend(sel, ee, er)
Call
📦02
Module
sass:selector
@use
🔗03
Result
original + extended
Output
📚04
Miss
returns as-is
Detail
✓05
Alt
replace to swap
Compare
❓ Frequently Asked Questions
selector.extend($selector, $extendee, $extender) returns a copy of $selector rewritten as if $extender { @extend $extendee; } ran. It keeps matches of $extendee and adds forms that use $extender. Example: extend("a.disabled", "a", ".link") becomes a.disabled, .disabled.link.
extend keeps the original selector and adds extended variants (a.disabled, .disabled.link). replace swaps $original for $replacement and drops the original match (.disabled.link only).
Official docs: if $selector does not contain $extendee, the function returns $selector unchanged.
No. Arguments may contain placeholder selectors, but not parent selectors.
Yes. selector-extend($selector, $extendee, $extender) is the legacy global name. Prefer selector.extend after @use "sass: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 describe selector.extend as returning a copy of $selector modified with an @extend rule—so you can use the same unification engine without writing the at-rule in place.
selector.extend() rewrites selectors with @extend-style unification: keep the original, add extender forms, and leave the value alone when $extendee is missing. Prefer selector.replace when you need a full swap, and avoid parent selectors.