Skip to content

LESS Selector Variables

Sometimes a selector's name itself needs to be dynamic, generated from a variable rather than hardcoded. LESS supports this through interpolation syntax, @{name}, embedded directly inside a selector.

What Are Selector Variables?

Wrapping a variable name in curly braces after an at sign, @{name}, tells LESS to substitute the variable's value directly into the surrounding text, in this case, a selector. This is different from using @name alone, which only works for full property values, not partial selector text.

Selector variables are especially useful in recursive mixins that generate a series of numbered or named utility classes.

@component: banner;

.@{component} {
  padding: 1rem;
  background: #f3f4f6;
}

Compiles to .banner { padding: 1rem; background: #f3f4f6; }, the interpolated variable becomes part of the class name.

Selector Interpolation Syntax

.@{variable-name} {
  property: value;
}

.prefix-@{variable-name} {
  property: value;
}
  • Curly braces are required for interpolation, @{name}, not just @name, when embedding a variable inside a selector.
  • Interpolation can appear anywhere within a selector, at the start, middle, or end of a class or ID name.
  • The interpolated value must resolve to valid selector-name characters; spaces or special characters will produce invalid CSS.
  • Selector variables are frequently combined with recursive mixins to generate a numbered series of classes.

Selector Variables Cheatsheet

Common interpolation patterns for building dynamic selectors.

Pattern Example Compiled Result
Full class name .@{name} { } .banner { } if @name: banner
Prefix + variable .col-@{i} { } .col-3 { } if @i: 3
Variable + suffix .@{name}-icon { } .banner-icon { }
ID interpolation #@{id} { } #header { } if @id: header
Attribute value [data-@{attr}] [data-theme] if @attr: theme

Generating a Series of Utility Classes

Combining selector interpolation with a recursive mixin lets you generate an entire family of related utility classes, like spacing or width utilities, from a single loop instead of writing each one by hand.

.generate-spacing(@i) when (@i > 0) {
  .mt-@{i} {
    margin-top: (@i * 4px);
  }
  .generate-spacing(@i - 1);
}

.generate-spacing(4);
// Produces .mt-1, .mt-2, .mt-3, .mt-4

Interpolation in Attribute Selectors

Selector interpolation also works inside attribute selectors, which is useful for theme systems that switch styles based on a data-* attribute driven by a shared variable name.

@theme-attr: theme;

[data-@{theme-attr}="dark"] {
  background: #111;
  color: white;
}

Interpolation vs a Plain Variable

A plain @name reference only works where a full value is expected, like a property value or a mixin argument. Embedding a variable inside a larger piece of text, like part of a selector, string, or property name, always requires the @{name} interpolation syntax.

  • Use @name when the variable is the entire value.
  • Use @{name} when the variable is embedded inside a larger selector, string, or property name.
  • Forgetting the curly braces in a selector context is a very common beginner mistake.

Common Mistakes

  • Writing .@name { } instead of .@{name} { } and getting a parse error, curly braces are required for selector interpolation.
  • Interpolating a variable whose value contains spaces or invalid selector characters, producing broken CSS.
  • Forgetting that interpolated selectors generated inside a loop still need to be genuinely unique to avoid duplicate rules.
  • Overusing generated utility classes instead of considering whether a smaller set of parametric mixins would be clearer.

Key Takeaways

  • @{name} interpolation embeds a variable's value directly into a selector, unlike a plain @name reference.
  • Interpolation works anywhere in a selector: prefixes, suffixes, IDs, and attribute selectors.
  • Combined with recursive mixins, selector interpolation generates entire families of utility classes.
  • Always use curly braces when a variable is embedded inside a larger piece of selector text.

Pro Tip

Reserve generated utility classes (via interpolation + recursion) for values that genuinely form a numeric or enumerable series, like spacing steps or grid columns; for one-off styles, a plain mixin is usually clearer.