Skip to content

[Proposal] Selector Suffixing for Native CSS Nesting #13205

@joelmiguelvalente

Description

@joelmiguelvalente

Proposal: Selector Suffixing for Native CSS Nesting

Summary

This proposal introduces a mechanism for generating derived selectors inside nested CSS rules using two new syntaxes:

&(suffix)
(suffix)

These express a suffix attached to the parent selector, enabling native BEM-style patterns without requiring Sass, Less, or PostCSS.

Example

.container {
    &(sm) { ... }
    (sm)  { ... }
}

Desired output:

.container-sm { ... }

Motivation

Many widely used CSS methodologies depend on suffixing a base selector:

  • .btn-primary
  • .alert-warning
  • .text-center
  • .container-sm
  • .card-header-title

Preprocessors allow this via:

.btn {
    &-primary { ... }
}

But &-primary cannot be standardized due to grammar ambiguity.
Native CSS currently has no way to express selector suffixes inside nested structures.

This proposal introduces a clean, unambiguous, and extensible syntax for such cases.

Why &-suffix Cannot Be Standardized

Native CSS cannot parse:

&-primary

because -identifier may be confused with:

  • a type selector
  • an ident token
  • an invalid selector
  • part of a compound selector

This prevents suffixing from being exposed in CSS Nesting.

Parentheses resolve the ambiguity.

Proposed Syntax

Option A — Explicit form: &(suffix)

.block {
    &(header) { ... }
    &(title)  { ... }
}

Produces:

.block-header { ... }
.block-title  { ... }

Option B — Minimal form: (suffix)

.block {
    (header) { ... }
}

Produces:

.block-header { ... }

Grammar Proposal

Option A

derived-selector:
    & '(' ident-token ')'

Option B

derived-selector:
    '(' ident-token ')'

Expansion rule (both options)

<parent-selector> "-" <suffix>

Examples

Simple component modifiers

.btn {
    &(primary) { ... }
    (outline)  { ... }
}

Produces:

.btn-primary { ... }
.btn-outline { ... }

Deep BEM-style derivation

.block {
    (header) {
        (title) { ... }
    }
}

Produces:

.block-header-title { ... }

Combining with regular nesting

.card {
    (header) {
        & span { ... }
    }
}

Produces:

.card-header span { ... }

Real-world utility example

.text {
    (start)       { text-align: left !important; }
    (end)         { text-align: right !important; }
    (center)      { text-align: center !important; }
    (decoration) {
        (none)        { text-decoration: none !important; }
        (underline)   { text-decoration: underline !important; }
        (line-through){ text-decoration: line-through !important; }
    }
    (lowercase)  { text-transform: lowercase !important; }
    (uppercase)  { text-transform: uppercase !important; }
    (capitalize) { text-transform: capitalize !important; }
    (wrap)       { white-space: normal !important; }
    (nowrap)     { white-space: nowrap !important; }
    (break) {
        word-break: break-word !important;
        overflow-wrap: break-word !important;
    }
    (danger)  { color: #FF0000; }
    (success) { color: #00FF00; }
}

Origin of the Idea (Initial Syntax Attempt)

When I first tried to simplify repetitive class families such as .text-*, .placeholder-*, and .container-*, I naturally gravitated toward a syntax already familiar in preprocessors:

.text {
    &-center { … }
}

This expands to:

.text-center { … }

This notation is intuitive, already widely used, and works conceptually as “append a suffix to the current selector.”

However, while testing native CSS nesting, this pattern does not work. The & operator in CSS nesting is explicitly designed for replacing the selector, not extending it as a suffix. Therefore, the syntax looked valid but produced invalid output.


Why the Syntax Evolved into (suffix) and &(suffix)

To avoid ambiguity with both:

  • the existing & replacement operator, and
  • attribute selectors such as [data-*]

I explored a more visually compact and explicit form.

This led to the proposed syntax:

.text {
    (center)  { … }   /* becomes .text-center */
    &(center) { … }   /* explicit suffix for cases that need it */
}

Reasons for this evolution:

  1. Parentheses already exist in CSS grammar (functions, calc(), var(), etc.) and are visually neutral.
  2. Unlike square brackets ([]), parentheses do not collide with selector semantics.
  3. (suffix) clearly communicates transformation rather than selection.
  4. It visually matches the mental model of “attach this to the parent name.”
  5. It avoids overloading [ ], which already has semantic meaning in selectors.
  6. For developers familiar with preprocessors, both (suffix) and &(suffix) feel natural.

Visual Comparison

What I intuitively wanted:

.text {
    &-center { text-align: center; }
}

But native CSS nesting cannot interpret it.
The improved conceptual model:

.text {
    (center) { text-align: center; }
}

Expands to:

.text-center { text-align: center; }

This syntax is:

  • concise
  • unambiguous
  • visually clean
  • consistent with how humans already reason about suffix utilities

Backward Compatibility

  • No existing CSS pattern uses standalone (ident) as a selector.
  • No conflict with pseudo-classes (: is required).
  • No conflict with properties or functions.
  • Browsers can ignore unknown constructs safely if necessary.

Questions for CSSWG

  1. Should suffix insertion always use "-" as the joining character?
  2. Should prefix-style derivation be considered?
  3. Should both syntaxes — &(suffix) and (suffix) — be standardized?
  4. Should chaining be allowed?
  5. Should multiple suffix blocks concatenate?

Optional Extension: BEM and Pseudo-selector Derivation Using Symbol Prefixes

In addition to the main proposal (&(suffix) and (suffix)), an optional extension may allow symbol-prefixed suffixes to support common naming conventions, especially BEM and pseudo-selectors.

Many codebases rely on structural naming such as:

  • BEM modifiers: .block--modifier
  • BEM elements: .block__element
  • Pseudo-class variants: .block:hover
  • Pseudo-element variants: .block::after

Allowing these patterns to be derived natively from nested CSS would significantly increase the expressiveness of native nesting and reduce reliance on preprocessors.

Proposed Optional Syntax

Inside a nested rule:

.block {
    (--warning) { ... }
    (__title)  { ... }
    (:hover)   { ... }
    (::after)  { ... }
}

Benefits

  • Mirrors established BEM naming conventions
  • Supports pseudo-class derivation in nesting
  • Syntactically unambiguous
  • Lightweight extension on top of the primary proposal

Note

This extension is not required for the core suffixing proposal but is included as a potential enhancement for CSSWG consideration.

Conclusion

Native CSS Nesting is an important step forward, but suffix derivation remains a major missing capability currently only possible through preprocessors.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions