'Create CSS custom properties from SCSS variables

I have an SCSS map of colour names and values. I want to create CSS custom properties from them like so:

SCSS

$colours:(
  "gray-500":    #f7fafc,
  "red-500":     #f56565,
  "green-500":   #48bb78
);

Desired resultant CSS

--gray-500:  #f7fafc;
--red-500:   #f56565;
--green-500: #48bb78;

I know how to loop through the map, but where I'm getting caught up is how to use the key as a custom property name, and how to prepend -- to it. All the examples I can find related to this topic involve manually typing out the custom property name - not gleaning it from the key of a map.

This is what I have so far:

@each $colour, $value in $colours {
    --#{$colour}:$value;
}

That generates an error: expected "{" with the caret pointing to the end of this line:

--#{$colour}:$value;

I'm using Dart Sass 1.23.7



Solution 1:[1]

On SCSS to CSS you can use the following:

:root {
  $colours:(
    "gray-500": #f7fafc,
    "red-500": #f56565,
    "green-500": #48bb78
  );

  @each $key_name, $value in $colours {
    --#{$key_name}: #{$value};
  }
}

demo on jsfiddle.net

On SASS to CSS you have to use the @each inside a :root element (or defining an element inside):

$colours:(
  "gray-500": #f7fafc,
  "red-500": #f56565,
  "green-500": #48bb78
);

:root {
  @each $key, $value in $colours {
    --#{$key}: #{$value};
  }
}

Solution 2:[2]

If you want to create CSS custom properties from nested sass map, you can do the following:

    @use "sass:meta";
    // create mixin
    @mixin map-scss-vars-into-css-vars($map, $prefix, $key: "") {
        @each $name, $value in $map {

            // copy the map key
            $key-copy: $key;
            // create name for CSS custom property that contains:
            // current key + child key from nested map
            $key: #{$key}-#{$name};
    
            @if meta.type-of($value) == "map" {
                // if value is a map, invoke it once more
                @include map-scss-vars-into-css-vars($value, $prefix, $key);
            } @else {
                --#{$prefix}#{$key}: #{$value};
            }
            // next iteration of loop should go with unchanged key
            $key: $key-copy;
        }
    }

How to use

// define your nested map

$config: (
    button: (
        primary: (
            color: red,
            background: blue,
        ),
        secondary: (
            color: yellow,
            background: green,
        ),
        tertiary: (
            color: white,
            background: black,
        ),
    ),
    input: (
        primary: (
            width: 100px,
        ),
    ),
);

// include magical mixin

:root {
    @include map-scss-vars-into-css-vars($config, 'my-cool-app');
}

// the result is astonishing

--my-cool-app-button-primary-color: red;
--my-cool-app-button-primary-background: blue;
--my-cool-app-button-secondary-color: yellow;
--my-cool-app-button-secondary-background: green;
--my-cool-app-button-tertiary-color: white;
--my-cool-app-button-tertiary-background: black;
--my-cool-app-input-primary-width: 100px;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Piosek