Maps
Sass maps are key/value collections — ordered, immutable, and ideal for storing design tokens, breakpoints, theme palettes, anything you want to look up by name. The sass:map module gives you a clean API.
map.get, map.set, theming patterns
EXAMPLE
// 1) Declare a map
$colors: (
'primary': #4f46e5,
'secondary': #14b8a6,
'danger': #ef4444,
'warning': #f59e0b,
'success': #22c55e,
);
$breakpoints: (
'sm': 640px,
'md': 768px,
'lg': 1024px,
'xl': 1280px,
);
// 2) Use the sass:map module (always @use, not @import)
@use 'sass:map';
@use 'sass:list';
@use 'sass:meta';
// 3) Read values
.btn-primary {
background: map.get($colors, 'primary');
color: map.get($colors, 'primary'); // safe — returns null if missing
}
// 4) Insert / overwrite (returns a NEW map; Sass maps are immutable)
$colors: map.set($colors, 'accent', #ff8a00);
$colors: map.merge($colors, ('muted': #6b7280, 'border': #e5e7eb));
// 5) Loop over a map → @each
@each $name, $value in $colors {
.text-#{$name} { color: $value; }
.bg-#{$name} { background: $value; }
.border-#{$name} { border-color: $value; }
}
// 6) Nested maps — theme system
$theme: (
'light': (
'bg': #ffffff,
'text': #0f172a,
'border': #e5e7eb,
),
'dark': (
'bg': #0f172a,
'text': #f1f5f9,
'border': #1e293b,
),
);
@function token($mode, $key) {
$mode-map: map.get($theme, $mode);
@if not $mode-map { @error "Unknown theme mode '#{$mode}'"; }
@return map.get($mode-map, $key);
}
:root {
@each $key, $_ in map.get($theme, 'light') {
--#{$key}: #{token('light', $key)};
}
}
.dark {
@each $key, $_ in map.get($theme, 'dark') {
--#{$key}: #{token('dark', $key)};
}
}
body {
background: var(--bg);
color: var(--text);
}
// 7) Responsive breakpoints from a map
@mixin respond($name) {
$value: map.get($breakpoints, $name);
@if not $value { @error "Unknown breakpoint '#{$name}'"; }
@media (min-width: #{$value}) { @content; }
}
.hero {
padding: 2rem;
@include respond('md') { padding: 4rem; }
@include respond('lg') { padding: 6rem; }
}
// 8) Spacing scale
$space: (
'0': 0,
'1': 0.25rem,
'2': 0.5rem,
'3': 0.75rem,
'4': 1rem,
'6': 1.5rem,
'8': 2rem,
'12': 3rem,
);
@each $name, $value in $space {
.m-#{$name} { margin: $value; }
.mx-#{$name} { margin-inline: $value; }
.my-#{$name} { margin-block: $value; }
.p-#{$name} { padding: $value; }
}
// 9) Inspecting maps
.debug {
keys: map.keys($colors); // ('primary', 'secondary', 'danger', …)
values: map.values($colors); // colors
size: list.length(map.keys($colors));
}
// 10) has-key — safe lookup
@function safe-color($name) {
@if not map.has-key($colors, $name) {
@warn "Color '#{$name}' missing — falling back to primary";
@return map.get($colors, 'primary');
}
@return map.get($colors, $name);
}
// 11) Deep get — nested key path
@function deep-get($map, $keys...) {
@each $key in $keys {
$map: map.get($map, $key);
@if $map == null { @return null; }
}
@return $map;
}
.dark-bg { background: deep-get($theme, 'dark', 'bg'); }
// 12) Module pattern — keep design tokens in one file
// _tokens.scss
@forward 'colors' as color-*; // exposes color-$primary etc.
// 13) Common bugs
// • Using @import — deprecated, all globals leak; use @use 'sass:map'
// • Sass maps are IMMUTABLE — map.set returns a new map, doesn't mutate
// • Trailing commas in some old parsers — modern Dart Sass allows them
// • Forgetting #{$value} string interpolation in selectors and media queries
// • Using map.get with a missing key — returns null silently; add @error or @warn for required keys
Why it matters
Maps are the cleanest way to store design tokens — spacing scales, breakpoints, theme palettes — and pair beautifully with @each for generating utility classes. Wrap map.get in a function that errors on missing keys; the build-time crash is far easier to fix than a silent null shipping to production.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
$theme: (primary: #04AA6D, danger: #c00);
.btn { background: map-get($theme, primary); }
Try it Yourself »
Discussion
Loading…