Skip to content

Sass: @each

How to use Sass' @each rule to loop through lists, maps, and nested lists for dynamic CSS generation with variables and destructuring.

The @each rule makes it easy to emit styles or evaluate code for each element of a list or each pair in a map. It's great for repetitive styles that only have a few variations between them, such as generating icon classes, theme colors, or breakpoint-specific rules.

It's usually written @each <variable> in <expression> { ... }, where the expression returns a list. The block is evaluated for each element of the list in turn, which is assigned to the given variable name.

Iterating a List

The simplest form loops over each element of a list and assigns it to a single variable.

The .scss file:

$sizes: 40px, 50px, 80px;

@each $size in $sizes {
  .icon-#{$size} {
    font-size: $size;
    height: $size;
    width: $size;
  }
}

The .css file:

.icon-40px {
  font-size: 40px;
  height: 40px;
  width: 40px;
}

.icon-50px {
  font-size: 50px;
  height: 50px;
  width: 50px;
}

.icon-80px {
  font-size: 80px;
  height: 80px;
  width: 80px;
}

Practical example: color palette

$colors: (
  "blue":   #4a90d9,
  "green":  #5cb85c,
  "red":    #d9534f,
  "orange": #f0ad4e,
);

// ...or a plain list:
$names: blue, green, red, orange;

@each $name in $names {
  .text-#{$name} {
    color: map-get($colors, $name);
  }
}

With Maps

You can also use @each to iterate over every key/value pair in a map by writing it @each <variable>, <variable> in <expression> { ... }. The key is assigned to the first variable name, and the value (element) is assigned to the second.

The .scss file:

$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f");

@each $name, $glyph in $icons {
  .icon-#{$name}:before {
    display: inline-block;
    font-family: "Icon Font";
    content: $glyph;
  }
}

The .css file:

.icon-eye:before {
  display: inline-block;
  font-family: "Icon Font";
  content: "\f112";
}

.icon-start:before {
  display: inline-block;
  font-family: "Icon Font";
  content: "\f12e";
}

.icon-stop:before {
  display: inline-block;
  font-family: "Icon Font";
  content: "\f12f";
}

Practical example: theme colors

$themes: (
  "primary":   #007bff,
  "secondary": #6c757d,
  "success":   #28a745,
  "danger":    #dc3545,
  "warning":   #ffc107,
);

@each $name, $color in $themes {
  .btn-#{$name} {
    background-color: $color;
    color: white;

    &:hover {
      background-color: darken($color, 10%);
    }
  }
}

This generates a .btn-primary, .btn-secondary, .btn-success, etc., each with its own color and a darkened hover state, from a single concise block.

Practical example: breakpoints

$breakpoints: (
  "sm":  576px,
  "md":  768px,
  "lg":  992px,
  "xl":  1200px,
);

@each $name, $value in $breakpoints {
  @media (min-width: $value) {
    .container-#{$name} {
      max-width: $value;
    }
  }
}

Destructuring

If you have a list of lists, you can use @each to automatically assign variables to each of the values from the inner lists by writing it @each <variable...> in <expression> { ... }.

This is known as destructuring, since the variables match the structure of the inner lists. Each variable name is assigned to the value at the corresponding position in the list, or null if the list doesn't have enough values.

The .scss file:

$icons:
  "eye" "\f112" 12px,
  "start" "\f12e" 16px,
  "stop" "\f12f" 10px;

@each $name, $glyph, $size in $icons {
  .icon-#{$name}:before {
    display: inline-block;
    font-family: "Icon Font";
    content: $glyph;
    font-size: $size;
  }
}

The .css file:

@charset "UTF-8";
.icon-eye:before {
  display: inline-block;
  font-family: "Icon Font";
  content: "\f112";
  font-size: 12px;
}

.icon-start:before {
  display: inline-block;
  font-family: "Icon Font";
  content: "\f12e";
  font-size: 16px;
}

.icon-stop:before {
  display: inline-block;
  font-family: "Icon Font";
  content: "\f12f";
  font-size: 10px;
}

Here each inner list ("eye" "\f112" 12px) is split across three variables: $name, $glyph, and $size.

Uneven inner lists

If an inner list has fewer values than variables, the extra variables are assigned null:

$data:
  ("a" 1px),
  ("b" 2px "extra"),
  ("c");  // only one element

@each $name, $value, $extra in $data {
  @debug "#{$name} => value: #{$value}, extra: #{$extra}";
}
// a => value: 1px, extra: null
// b => value: 2px, extra: "extra"
// c => value: null, extra: null

Why maps work with destructuring

SCSS vs. Sass Syntax

@each works in both syntaxes. In the indented .sass syntax, the block is indicated by indentation (no braces, no semicolons):

$sizes: 40px, 50px, 80px

@each $size in $sizes
  .icon-#{$size}
    font-size: $size
    height: $size
    width: $size

Compiles to the same CSS as the SCSS version.

Using @each with Index: meta.load-css / list.index

@each does not give you the loop index directly. If you need an index (for example, for nth-child selectors), use the list.index() function alongside it, or fall back to @for:

@use "sass:list";

$columns: ("one", "two", "three", "four");

@each $name in $columns {
  $i: list.index($columns, $name);

  .col-#{$name} {
    order: $i;
  }
}

Compiles to:

.col-one   { order: 1; }
.col-two   { order: 2; }
.col-three { order: 3; }
.col-four  { order: 4; }

@each vs @for

Feature @each @for
Iterates over Elements of a list or pairs in a map A range of numbers
Provides The current element (and/or key) A counter variable ($i)
Best for Named collections, key/value data Numeric ranges, repeating a fixed count

Use @each when your data is a named collection (icons, theme colors, breakpoints); use @for when you need a numeric counter (e.g., generating 12 grid columns by index).

Summary

Form Syntax Assigns
List @each $var in $list { ... } One element per iteration
Map @each $key, $val in $map { ... } Key + value per iteration
Destructuring @each $a, $b, $c in $list-of-lists { ... } Positional values from each inner list (missing → null)

Key points to remember:

  1. @each loops over lists and maps, not numeric ranges (use @for for those).
  2. Use interpolation (#{...}) to embed variables into selectors or property names.
  3. Maps are just lists of key/value pairs, so map iteration is a special case of destructuring.
  4. Missing values in destructuring are filled with null, not an error.
  5. Need an index? Use list.index() or switch to @for.
Navigation