Looking for a Front-End Developer and Design Systems Practitioner?

I currently have some availabilty. Let's talk!.

Always Twisted

A Design Tokens Workflow (part 11)

Creating Sass-backed CSS Custom Properties With Style Dictionary

  1. Getting Started With Style Dictionary
  2. Outputting to Different Formats with Style Dictionary
  3. Beyond JSON: Exploring File Formats for Design Tokens
  4. Converting Tokens with Style Dictionary
  5. Organising Outputs with Style Dictionary
  6. Layers, referencing tokens in Style Dictionary
  7. Implementing Light and Dark Mode with Style Dictionary
  8. Implementing Light and Dark Mode with Style Dictionary (part 2)
  9. Implementing Multi-Brand Theming with Style Dictionary
  10. Creating Multiple Themes with Style Dictionary
  11. Creating Sass-backed CSS Custom Properties With Style Dictionary – You are here
  12. Creating a Penpot Design Tokens Format with Style Dictionary
On This Page:

Whilst writing my recent article on where and when I choose to use Sass variables or CSS Custom Properties in a project I thought to myself “you could automate this bit using style dictionary”. As that article is published I’ve quickly opened up a new markdown file to write this. In this article we will look at how we can use our design tokens to not only generate Sass variables, but generate CSS custom properties that will make use of the Sass variables using interpolation.

Implementing Spacing Tokens

Let's create a sample token structure that combines scale definitions with component-specific applications. tokens/base/spacing.tokens

Code languagejson
{
"spacing": {
"100": {
"$value": "0.125rem",
"$type": "spacing"
},
"200": {
"$value": "0.25rem",
"$type": "spacing"
},
"300": {
"$value": "0.5rem",
"$type": "spacing"
},
"400": {
"$value": "1rem",
"$type": "spacing"
},
"800": {
"$value": "2rem",
"$type": "spacing"
}
}
}

tokens/semantic/spacing.tokens

Code languagejson
{
"component": {
"margin": {
"inline": {
"$value": "{spacing.400.$value}",
"$type": "spacing"
},
"block": {
"$value": "{spacing.400.$value}",
"$type": "spacing"
}
},
"padding": {
"inline": {
"$value": "{spacing.100.$value}",
"$type": "spacing"
},
"block": {
"$value": "{spacing.100.$value}",
"$type": "spacing"
}
}
}
}

Style Dictionary Configuration

Next we need to create a new build script that will use Style Dictionary. What we want to do is:

Code languagejavascript
import { globSync } from 'glob'; // For file pattern matching
import StyleDictionary from 'style-dictionary';
// Find all token files matching the pattern
const tokenFiles = globSync('src/tokens/**/*.tokens');
// Header comment for generated files
const HEADER_COMMENT = `// Do not edit directly, this file was auto-generated.\n\n`;
// Configure Style Dictionary instance
const myStyleDictionary = new StyleDictionary({
source: tokenFiles,
platforms: {
sass_base: {
transformGroup: 'scss', // Use standard SCSS transforms
buildPath: 'build/sass/base/',
files: [{
destination: '_base-tokens.scss',
format: 'scss/variables', // SCSS variables format
filter: (token) => token.filePath.includes('base'), // Only process base tokens
}],
},
css_semantic: {
transformGroup: 'scss', // Use SCSS transforms
buildPath: 'build/sass/semantic/',
files: [{
destination: 'variables.scss',
format: 'css/sass-ref', // Custom format defined in hooks
filter: (token) => token.filePath.includes('semantic'), // Only process semantic tokens
}],
},
},
// Custom format definitions
hooks: {
formats: {
// Custom CSS format that references Sass variables
'css/sass-ref': function ({ dictionary }) {
// Process all tokens in the dictionary
const tokens = dictionary.allTokens.map((token) => {
const isReference = typeof token.original.$value === 'string' &&
token.original.$value.startsWith('{') &&
token.original.$value.endsWith('}');
const sassVariable = isReference
? `$${token.original.$value
.slice(1, -1) // Remove curly braces
.replace(/\.\$value/g, '') // Remove .$value suffix first
.replace(/\./g, '-')}` // Then convert remaining dots to hyphens
: `$${token.name}`;
return ` --${token.name}: #{${sassVariable}};`;
}).join('\n');
// Combine header, Sass import, and CSS variables
return `${HEADER_COMMENT}@use "../base/_base-tokens.scss";\n\n:root {\n${tokens}\n}`;
}
}
}
});
// Execute the build process for all platforms
myStyleDictionary.buildAllPlatforms();
console.log('Build completed!');

Key Script Components

The code for this example can be found on this branch of the repo this series has been using

Generated Output Structure

The script produces two critical files. These files are:

Base Tokens (Sass)

_base-tokens.scss

Code languagescss
$spacing-100: 0.125rem;
$spacing-200: 0.25rem;
$spacing-300: 0.5rem;
$spacing-400: 1rem;
$spacing-800: 2rem;

Semantic Tokens (CSS)

_variables.scss

Code languagescss
@use "../base/_base-tokens.scss";
:root {
--component-margin-inline: #{$spacing-400};
--component-margin-block: #{$spacing-400};
--component-padding-inline: #{$spacing-100};
--component-padding-block: #{$spacing-100};
}

This Style Dictionary configuration helps solve several challenges in modern design systems:

  1. Single Source of Truth: Token updates propagate through both Sass and CSS layers.
  2. Contextual Adaptation: Component-specific overrides maintain design consistency
  3. Toolchain Integration: Automates the Sass to CSS bridge while preserving both paradigms.
  4. Scale Maintenance: Spacing ratios remain consistent across primitive and semantic layers.

By combining Style Dictionary's transformation power with Sass's preprocessing capabilities, we can create a future-proof system that works seamlessly with CSS-in-JS solutions, traditional Sass projects, and modern CSS-only architectures and more.

Struggling to create documentation that clearly explains token usage for all team members?

I’ll build comprehensive yet simple documentation for your design tokens.

get in touch!