Skip to content

Sass Maps — Complete Guide

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Sass Maps. We cover key concepts, practical examples, and best practices to help you master this topic.

Sass maps store key-value pairs for structured configuration using sass:map module with functions for access, merge, iteration, and deep nesting.

What You'll Learn

  • Creating and accessing maps
  • Map manipulation (merge, remove, keys, values)
  • Deep/nested maps
  • Iterating maps with @each
  • Using maps for themes, breakpoints, and configuration
  • Functions that work with maps for lookup

Why It Matters

  • Maps provide structured data like JavaScript objects
  • Centralized configuration reduces scatter
  • Maps enable dynamic theme generation
  • Nested maps model complex design tokens

Real-World Use

  • A breakpoint map drives all responsive queries
  • A theme map contains all design tokens
  • A variant map generates component styles
  • A z-index map centralizes layering
flowchart LR
  A[Sass Maps] --> B[Keys]
  A --> C[Values]
  B --> D[map-get, map-keys]
  C --> E[map-values, map-has-key]
  A --> F[Iteration]
  F --> G[Generate CSS from data]

Working with Maps

Code Example: Creating and Accessing Maps

@use 'sass:map';

// Basic map
$breakpoints: (
    'sm': 480px,
    'md': 768px,
    'lg': 1024px,
    'xl': 1280px
);

// Accessing values
$md-width: map.get($breakpoints, 'md');         // 768px
$lg-width: map.get($breakpoints, 'lg');         // 1024px

// Check if key exists
$has-sm: map.has-key($breakpoints, 'sm');        // true
$has-xxl: map.has-key($breakpoints, 'xxl');      // false

// Get all keys or values
$keys: map.keys($breakpoints);                   // 'sm', 'md', 'lg', 'xl'
$values: map.values($breakpoints);               // 480px, 768px, 1024px, 1280px

// Count entries
$count: map.length($breakpoints);                // 4

// Using map values
@function bp($name) {
    @if map.has-key($breakpoints, $name) {
        @return map.get($breakpoints, $name);
    } @else {
        @error "Unknown breakpoint: #{$name}.";
    }
}

.container {
    max-width: bp('lg') - 40px;                  // 984px
}

@media (min-width: bp('md')) {
    .sidebar { width: 300px; }
}

Expected output: map.get() retrieves values by key. map.has-key() checks existence. map.keys() and map.values() extract all keys or values. The bp() function provides a clean lookup API.

Code Example: Map Manipulation

@use 'sass:map';

// Merge maps
$default-theme: (
    'primary': #0066CC,
    'secondary': #6c757d,
    'font-size': 16px
);

$dark-overrides: (
    'primary': #4da6ff,
    'bg': #1a1a2e,
    'text': #e0e0e0
);

$dark-theme: map.merge($default-theme, $dark-overrides);
// Result: (primary: #4da6ff, secondary: #6c757d, font-size: 16px, bg: #1a1a2e, text: #e0e0e0)
// Note: $dark-overrides keys overwrite $default-theme keys

// Merge with deep merge (for nested maps)
$shallow: map.merge($default-theme, $dark-overrides);  // Shallow merge
$deep: map.deep-merge($default-theme, $dark-overrides); // Deep merge (recursive)

// Remove keys
$reduced: map.remove($default-theme, 'secondary');
// Result: (primary: #0066CC, font-size: 16px)

// Set a value (add or update)
$updated: map.set($default-theme, 'primary', #ff6600);
// Result: (primary: #ff6600, secondary: #6c757d, font-size: 16px)

// Deep set nested value
$nested: map.set($default-theme, 'typography', 'h1', 2.5rem);
// Result: (primary: ..., secondary: ..., font-size: ..., typography: (h1: 2.5rem))

// Check map depth
$is-deep: map.depth($nested);  // 2

Expected output: map.merge() combines two maps. map.deep-merge() merges deeply nested maps recursively. map.set() updates or adds entries. map.depth() checks nesting level.

Code Example: Iterating Maps

@use 'sass:map';

// Basic @each with keys and values
$theme-colors: (
    'primary': #0066CC,
    'secondary': #6c757d,
    'success': #28a745,
    'danger': #dc3545,
    'warning': #ffc107,
    'info': #17a2b8
);

@each $name, $color in $theme-colors {
    .text-#{$name} { color: $color; }
    .bg-#{$name} { background: $color; }
    .border-#{$name} { border-color: $color; }

    .btn-#{$name} {
        background: $color;
        color: #fff;

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

// Iterate with keys only
@each $name in map.keys($theme-colors) {
    .badge-#{$name} {
        background: map.get($theme-colors, $name);
    }
}

// Nested map iteration
$components: (
    'card': (
        'padding': 1.5rem,
        'radius': 8px,
        'shadow': 0 2px 8px rgba(0,0,0,0.1)
    ),
    'button': (
        'padding': 0.75rem 1.5rem,
        'radius': 4px,
        'font-size': 1rem
    )
);

@each $component, $props in $components {
    .#{$component} {
        @each $prop, $value in $props {
            @if $prop == 'padding' {
                padding: $value;
            } @else if $prop == 'radius' {
                border-radius: $value;
            } @else if $prop == 'shadow' {
                box-shadow: $value;
            } @else if $prop == 'font-size' {
                font-size: $value;
            }
        }
    }
}

Expected output: @each with maps iterates over key-value pairs. Utility classes (text-primary, bg-primary) are generated automatically. Nested maps enable multi-level component configuration.

Code Example: Advanced Map Patterns

@use 'sass:map';

// Design token map with nested structure
$tokens: (
    'color': (
        'brand': (
            'primary': #0066CC,
            'secondary': #6c757d,
            'accent': #ff6600
        ),
        'neutral': (
            'white': #ffffff,
            'gray-100': #f8f9fa,
            'gray-200': #e9ecef,
            'gray-800': #343a40,
            'black': #000000
        ),
        'semantic': (
            'success': #28a745,
            'error': #dc3545,
            'warning': #ffc107,
            'info': #17a2b8
        )
    ),
    'spacing': (
        'xs': 4px,
        'sm': 8px,
        'md': 16px,
        'lg': 24px,
        'xl': 32px,
        'xxl': 48px
    ),
    'typography': (
        'font-family': (
            'sans': ('Inter', system-ui, sans-serif),
            'mono': ('Fira Code', monospace)
        ),
        'font-size': (
            'xs': 0.75rem,
            'sm': 0.875rem,
            'base': 1rem,
            'lg': 1.125rem,
            'xl': 1.25rem,
            '2xl': 1.5rem,
            '3xl': 2rem
        )
    ),
    'breakpoint': (
        'sm': 480px,
        'md': 768px,
        'lg': 1024px,
        'xl': 1280px
    ),
    'z-index': (
        'dropdown': 100,
        'sticky': 200,
        'nav': 300,
        'overlay': 400,
        'modal': 500
    )
);

// Deep token access function
@function token($keys...) {
    $current: $tokens;

    @each $key in $keys {
        @if map.has-key($current, $key) {
            $current: map.get($current, $key);
        } @else {
            @error "Token not found: #{$keys}";
        }
    }

    @return $current;
}

// Usage
.btn-primary {
    background: token('color', 'brand', 'primary');     // #0066CC
    padding: token('spacing', 'sm') token('spacing', 'md'); // 8px 16px
    font-family: token('typography', 'font-family', 'sans');
    font-size: token('typography', 'font-size', 'base');
    z-index: token('z-index', 'dropdown');                // 100
}

@media (min-width: token('breakpoint', 'md')) {
    .container {
        max-width: 720px;
    }
}

// Theming with map deep-merge
$dark-tokens: map.deep-merge($tokens, (
    'color': (
        'brand': (
            'primary': #4da6ff
        ),
        'neutral': (
            'white': #1a1a2e,
            'gray-100': #2d2d44,
            'black': #ffffff
        )
    )
));

[data-theme="dark"] {
    background: token('color', 'neutral', 'white');
    color: token('color', 'neutral', 'black');
}

Expected output: The token() function provides dot-notation-like access to nested maps. Deep merge enables theme overrides that only change specific tokens. A single $tokens map drives all design decisions.

Common Mistakes

  1. Using map functions without @use 'sass:map' — Map functions require the sass:map module. Without it, they cause compilation errors.
  2. Accessing missing keys — map.get() returns null for missing keys. Use map.has-key() to check first, or use @error for clear messages.
  3. Shallow merge when deep merge is needed — map.merge() overwrites entire nested values. Use map.deep-merge() for recursive merging.
  4. Hard-coded map keys in multiple places — Access map values with lookup functions. Hard-coded keys scatter the configuration.
  5. Not using quoted string keys — Keys can be unquoted strings or quoted. Consistency matters. Quoted strings are more predictable.
  6. Too much nesting — Maps nested 5+ levels deep are hard to read and maintain. Keep to 2-3 levels.
  7. Mutating shared maps — Functions like map.set() return new maps. If you modify a global map, other modules see the original.

Practice Questions

  1. How do you access a value in a Sass map? map.get($map, $key) returns the value for the key.
  2. What is the difference between map.merge() and map.deep-merge()? merge() shallowly combines maps. deep-merge() recursively merges nested maps.
  3. How do you iterate over a map's keys and values? @each $key, $value in $map { ... }
  4. What does map.has-key() return? Returns true if the map contains the key, false otherwise.

FAQ

Should map keys be quoted or unquoted?

Quoted strings are more predictable and avoid conflicts with CSS property names. Unquoted keys work but can cause issues.

Can a map value be another map?

Yes. Nested maps are common for design token trees. Access them with the token() function pattern.

How do I handle optional map keys?

Use map.has-key() to check before accessing. Provide default values with map-get($map, $key) or null checks.

Mini Project

Build a complete design token system using nested Sass maps. Create a $tokens map with: color (brand, neutral, semantic), spacing (xs through xxl), typography (font-family, font-size, line-height), breakpoint (sm through xl), and z-index. Create a token() function for deep access. Create a dark theme variant using map.deep-merge(). Use @each to generate utility classes (text-, bg-, font-, p-, m-*) from the tokens. Build a sample page (header, buttons, cards, grid layout, alerts) that uses only token values. Demonstrate that changing one token value updates the entire page.

What's Next

Continue with Lesson 14: Sass and CSS Output to learn controlling CSS output from Sass.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro