@design-tokens-manager/style-dictionary-css-layers
v0.0.1
Published
Style Dictionary plugin that emits CSS @layer blocks from $extensions layer metadata on design tokens.
Maintainers
Readme
Style Dictionary CSS @layer plugin
A Style Dictionary plugin that emits CSS
@layer blocks from design token metadata, so component-level custom
properties land in a deliberately weak, overridable layer — no specificity
hacks, no source-order drama.
Read the background on the idea in Extending Design Tokens With CSS
@Layer and Chris Coyier's original post on horizontal thinking in CSS
@layer.
Why
CSS @layer is a delivery concern, not a design decision, so it shouldn't
live in a token's $value or $type. This plugin reads layer information
from a namespaced $extensions block on each token (per the DTCG Format
Module) and groups the
generated CSS custom properties into matching @layer blocks.
Tokens with no layer metadata are emitted in a plain :root block, untouched.
Install
If you are using this repository directly from GitHub, clone or download it and install it into your project from that local checkout:
git clone https://github.com/<owner>/sd-css-layers.git
cd your-project
npm install --save-dev ./sd-css-layers style-dictionaryIf you later publish the package to npm, the equivalent install command is:
npm install --save-dev sd-css-layers style-dictionaryUsage
1. Add layer metadata to your tokens
{
"card": {
"background": {
"$value": "#1a1a1a",
"$type": "color",
"$extensions": {
"com.example/css-layer": {
"layer": "components.card"
}
}
}
}
}2. Register the format in your Style Dictionary config
import StyleDictionary from 'style-dictionary';
import { cssLayersFormat } from 'sd-css-layers';
cssLayersFormat(StyleDictionary);
export default {
source: ['tokens/**/*.json'],
platforms: {
css: {
transformGroup: 'css',
files: [
{
destination: 'variables.css',
format: 'css/variables-with-layers',
},
],
},
},
};3. Build
npx style-dictionary buildOutput
:root {
--color-brand: #f97316;
}
@layer components.card {
:root {
--card-background: #1a1a1a;
--card-color: #ffffff;
}
}Tokens without the com.example/css-layer extension are written to the plain :root block above any @layer blocks, so they behave as normal unlayered CSS and can still override anything inside a layer.
API
The package exports a few named functions in case you want to build your own format on top of the same grouping logic:
| Export | Description | |---|---| | cssLayersFormat(StyleDictionary) | Registers the css/variables-with-layers format on the given Style Dictionary instance. | | getTokenLayer(token) | Reads the com.example/css-layer layer name off a single token, if present. | | groupTokensByLayer(tokens) | Splits an array of tokens into a Map of layer name → tokens, plus an unlayered array. | | renderCss({ layerGroups, unlayered }) | Renders the final CSS string from grouped tokens. | | CSS_LAYER_EXTENSION_KEY | The extension namespace string, com.example/css-layer. | | FORMAT_NAME | The registered format name, css/variables-with-layers. |
Namespacing your own extension key
com.example/css-layer is a placeholder namespace used in the article and examples. In your own project, swap it for your own reverse-domain namespace (e.g. com.yourcompany/css-layer) by importing the grouping helpers directly and writing a small wrapper format, or by forking index.js and changing the constant.
Example
See the ~example/~ directory for a full token set (card.json, button.json, global.json), a Style Dictionary config, and the expected CSS output.
npm run build:exampleTests
npm testRuns unit tests against the grouping/rendering logic plus an end-to-end Style Dictionary build using Node's built-in test runner.
Roadmap
This is currently a vendor extension, which is exactly what $extensions is for. If a $layer-style property is ever proposed as a first-class DTCG spec property (in the way $deprecated moved from convention to reserved keyword), this plugin would migrate to read that instead, with the namespaced extension kept as a fallback for older token sources.
