Skip to content

Expressions & Calculations

The ${...} expression produces values at compile time inside .luis. It works inside @fun, @for, and @if; it can also be used directly in selector and declaration values.

This page also covers the former Expression Engine content.


TypeExample
Arithmetic${i + j}, ${i * 4}, ${i / 2}
String concatenation${'btn' + '-' + size}
Compile-time normal var${var(--prefix) + '-' + name}
Compile-time object key var${var(--theme.prefix) + '-' + name}
Compile-time array index var${var(--sizes[0])}, ${var(--sizes[ind])}
Compile-time array item key${var(--breakpoints[0].name)}, ${var(--breakpoints[ind].name)}
Compile-time object bracket${var(--colors[key])}
Local array index access${arr[0]}
Local array index + key${arr[0].name}
Local object key access${obj.key}, ${obj.name}
Parenthesized expression${(i + j) * 2}

  • ${...} can be used not only inside @for or @fun but also in selector and declaration values
  • If the expression produces a string or calculation result, it is written to output at compile time
  • When concatenating with a string literal, the literal part must be quoted: 'btn', "sm"
  • Unquoted tokens like color, prefix, btn are interpreted as identifiers, not string literals

Can also be used outside @for or @fun

--prefix: btn;
--factor: 4;
.${var(--prefix) + '-size'} {
font-size: ${var(--factor) * 4}px;
}

Generated CSS:

.btn-size { font-size: 16px; }

The four arithmetic operators are supported: +, -, *, /

@for(i, [1-4]) {
.p-${i} { padding: ${i * 4}px; }
.gap-${i} { gap: ${i * 8}px; }
}

Generated CSS:

.p-1 { padding: 4px; }
.p-2 { padding: 8px; }
.p-3 { padding: 12px; }
.p-4 { padding: 16px; }
.gap-1 { gap: 8px; }
.gap-2 { gap: 16px; }
.gap-3 { gap: 24px; }
.gap-4 { gap: 32px; }

Standard operator precedence applies: * and / first, then + and -. Use parentheses in ambiguous cases:

@for(i, [1-3]) {
.item-${(i + 1) * 2} { z-index: ${(i + 1) * 2}; }
}

Generated CSS:

.item-4 { z-index: 4; }
.item-6 { z-index: 6; }
.item-8 { z-index: 8; }

The - operator behaves differently depending on context:

FormBehavior
${a - b}Mathematical subtraction if all operands are numbers
${prefix-name}Concatenation with - if at least one is a string
${prefix + '-' + name}Always string concatenation — explicit form, recommended

Use the explicit form in ambiguous cases:

/* Ambiguous — is prefix a string or number? */
.${prefix-size} { }
/* Explicit and always correct */
.${prefix + '-' + size} { }

The + operator behaves differently depending on context:

FormBehavior
${a + b}Mathematical addition if all operands are numbers
${prefix+name}Concatenation if at least one is a string
--prefix: btn;
--factor: 4;
--count: 6;
.${var(--prefix) + '-size'} {
font-size: ${var(--factor) * 4}px;
}
.${var(--prefix) + var(--factor)} {
font-size: ${var(--factor) * 4}px;
}
.size-${var(--count) + var(--factor)} {
font-size: ${var(--factor) * 4}px;
}

Output:

.btn-size {
font-size: 16px;
}
.btn4 {
font-size: 16px;
}
.size-10 {
font-size: 16px;
}

A value with a unit can be multiplied by a unitless number. The unit is carried to the output.

@fun: size(i) {
${i * 4};
}
.btn {
padding: @fun.size(3px);
margin: @fun.size(2px);
}

Generated CSS:

.btn {
padding: 12px;
margin: 8px;
}

With an array variable:

--scale: [1px-4px];
--factor: 3;
@for(i, var(--scale)) {
.space-${i} {
margin-top: ${i} * var(--factor);
}
}

Generated CSS:

.space-1px { margin-top: 3px; }
.space-2px { margin-top: 6px; }
.space-3px { margin-top: 9px; }
.space-4px { margin-top: 12px; }

Two var() can be multiplied directly in a declaration value — ${...} is not required:

--scale: [1px-3px];
--factor: 4;
.space {
margin-top: var(--factor) * var(--scale[0]);
}

Generated CSS:

.space {
margin-top: 4px;
}

var() multiplication with ${...} inside @for:

--scale: [1px-3px];
--factor: 4;
@for(i, var(--scale)) {
.space-${i} {
margin-top: ${i * var(--factor)};
}
}

Generated CSS:

.space-1px { margin-top: 4px; }
.space-2px { margin-top: 8px; }
.space-3px { margin-top: 12px; }

String values are concatenated with the + operator. String literals must be quoted.

--prefix: btn;
@for(size, [sm, md, lg]) {
.${var(--prefix) + '-' + size} {
font-size: 14px;
}
}

Generated CSS:

.btn-sm { font-size: 14px; }
.btn-md { font-size: 14px; }
.btn-lg { font-size: 14px; }

Inside @fun:

@fun: make-class(prefix, name) {
.${prefix + '__' + name} {
display: block;
}
}
@fun.make-class(card, body);
@fun.make-class(card, footer);

Generated CSS:

.card__body { display: block; }
.card__footer { display: block; }

The following var() forms are supported inside ${...}:

${var(--prefix) + '-' + size} /* CSS variable */
${var(--theme.prefix) + '-' + size} /* Object key */
${var(--sizes[0])} /* Array index */
${var(--sizes[ind])} /* Array index (loop variable) */
${var(--breakpoints[0].name)} /* Array item key */
${var(--breakpoints[ind].name)} /* Array item key (loop variable) */
${var(--colors[key])} /* Object bracket — only for object variables */
--color: A;
.${'color' + var(--color)} {
color: ${'#aa' + var(--color)};
}
.colorA { color: #aaA; }
--colorA: [A-F];
.${"color-" + var(--colorA[0])} {
color: ${"#aa" + var(--colorA[0])};
}
.color-A { color: #aaA; }
--colors: { primary: #111111; secondary: #222222; };
@for(key, [primary, secondary]) {
.text-${key} {
color: ${var(--colors[key])};
}
}
.text-primary { color: #111111; }
.text-secondary { color: #222222; }

Multiple iteration values can be calculated together in nested @for loops.

--x: [1-2];
--y: [1-3];
@for(i, var(--x)) {
@for(j, var(--y)) {
.m-${i + '-' + j} {
padding: ${i * j}px;
}
}
}

Generated CSS:

.m-1-1 { padding: 1px; }
.m-1-2 { padding: 2px; }
.m-1-3 { padding: 3px; }
.m-2-1 { padding: 2px; }
.m-2-2 { padding: 4px; }
.m-2-3 { padding: 6px; }

${i + '-' + j} in the selector does string concatenation, while ${i * j} in the property does multiplication.


Parentheses determine precedence in expressions with multiple operations.

--space: [0-3];
@for(i, var(--space)) {
.p-${i} { padding: ${(i + 2) * 3}px; }
}

Generated CSS:

.p-0 { padding: 6px; }
.p-1 { padding: 9px; }
.p-2 { padding: 12px; }
.p-3 { padding: 15px; }

For i = 0: (0 + 2) * 3 = 6, for i = 1: (1 + 2) * 3 = 9.


Local variables can be used inside @fun to store intermediate calculation results.

@fun: make-spacing(base) {
$sm: ${base};
$md: ${base * 2};
$lg: ${base * 4};
.space-sm { margin: ${sm}px; }
.space-md { margin: ${md}px; }
.space-lg { margin: ${lg}px; }
}
@fun.make-spacing(4);

Generated CSS:

.space-sm { margin: 4px; }
.space-md { margin: 8px; }
.space-lg { margin: 16px; }