Search code examples
sass

How to loop nested maps in SASS


I'm trying to loop nested maps in sass in order to create certain css variables for a list of themes.

I have a mape of themes like this:

$themes: (
    theme-1: (
        primary: (
            "el-background": #000,
            "el-background-hover": #0d0d0d,
            "el-color": #2c2f33,
            "el-link-color": #fff,
        ),
        secondary_1: (
            "el-background": #000,
            "el-background-hover": #ccc,
            "el-color": #f2f2f2,
            "el-link-color": #fff,
        )
    ),
    theme-2: (
        primary: (
            "el-background": #f90,
            "el-background-hover": #ccc,
            "el-color": #000,
            "el-link-color": #fff,
        ),
        secondary_1: (
            "el-background": #f2f2f2,
            "el-background-hover": #000,
            "el-color": #f2f2f2,
            "el-link-color": #fff,
        )
    )
);

I'm expecting a result like this in css:

.theme-1 {
    .primary {
        --el-background: ...;
        --el-background-hover: ...;
        --el-color: ...;
        --el-link-color: ...;
    }

    .secondary_1 {
        --el-background: ...;
        --el-background-hover: ...;
        --el-color: ...;
        --el-link-color: ...;
    }
}

.theme-2 {
    .primary {
        --el-background: ...;
        --el-background-hover: ...;
        --el-color: ...;
        --el-link-color: ...;
    }

    .secondary_1 {
        --el-background: ...;
        --el-background-hover: ...;
        --el-color: ...;
        --el-link-color: ...;
    }
}

How do I tweak this loop to achieve this? I think I need to wrap it in another @each but not sure how.

@mixin theme() {
    @each $theme, $map in $themes {
        .#{$theme} {
            @each $key,
            $value in $map {
                --#{$key}: #{$value};
            }
        }
    }
}

Solution

  • You just need to add another loop to go over values in 'primary' and 'secondary_1'. Something like this:

    @mixin theme() {
        @each $theme, $map in $themes {
            .#{$theme} {
                @each $key, $value in $map {
                  .#{$key} {
                    @each $varName, $varValue in $value {
                      --#{$varName}: #{$varValue};
                    }
                  }
                }
            }
        }
    }
    
    :root {
      @include theme();
    }
    

    Solution on SCSS playground