style-dictionary-utils is a collection of filters, transformers and formats for Style Dictionary that make working with w3c design tokens a lot easier.
Install the style-dictionary-utils as well as style-dictionary.
npm i -D style-dictionary-utils style-dictionaryIf you are not ready to upgrade to style dictinary version 3 you can continue using style-dictionary-utils by locking to v2 currently v2.4.1 version.
The easiest way to use style-dictionary-utils is to import the prepared StyleDictionary object into your build file:
// build.ts
import {StyleDictionary} from 'style-dictionary-utils'
const myStyleDictionary = new StyleDictionary()
// when using style dictionary 4 you whave to await the extend method
const extendedSd = await myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['color/hexAlpha', 'shadow/css'],
files: [
{
filter: 'isSource',
destination: 'tokens.ts',
format: 'javascript/esm',
},
],
},
},
})
extendedSd.buildAllPlatforms()Now all the included utilities* are available to you via the keys mentioned in the docs below.
You can still extend style dictionary with your own transformers and formats like before.
The only difference is that you must use the StyleDictionary object that you import from style-dictionary-utils.
// build.ts
import { StyleDictionary } from 'style-dictionary-utils'
StyleDictionary.registerTransform({
name: 'transform/pxToRem',
type: `value`,
transitive: true,
transform: () => // ...
})Look at the tests to get an idea how it works.
- Formats
- Transformers
- Filters
- Special Filter
The css/advanced format exports a token dictionary as a css file with css variables. It allows you to define media queries that can wrap specific parts of your css variables. If nothing is defined the entire file will be wrapped in a :root selector.
You can change the selector by defining it in file.options.selector.
You can define rules on a file level using file.options.rules. If one or more rules are defined, only tokens within any of the rules will be output. You can define as many rule objects within file.options.rules as you want. Tokens can be part of one or multiple rules.
A rule object may have any or all of the three properties atRule, selector and matcher.
selectoris a string that is wrapped around your css. If theselectoris undefined, the default selector or one define atfile.options.selectorwill be used. If you don't want a selector, set it tofalse.atRulecan be a string or array of strings, that are wrapped around the css andselectorwith the first being the outer layer.matcheris a filter function that returns true for tokens that should be included in the query. If you want to match all tokens, just return true from the matcher.
body[theme='dark'] {
--color-background-primary: #ff0000;
--color-background-secondary: #0000ff;
}
@media (min-width: 768px) {
body[theme='dark'] {
--color-button-primary: #c1c1c1;
--color-button-secondary: #007d79;
}
}myStyleDictionary.extend({
"platforms": {
"css": {
"transforms": //...,
"files": [{
// ...
"format": "css/advanced",
"options": {
selector: `body[theme="dark"]`, // defaults to :root; set to false to disable
rules: [
{
atRule: '@media (min-width: 768px)',
selector: `body[size="medium"]` // this will be used instead of body[theme="dark"]`
matcher: (token: StyleDictionary.TransformedToken) => token.filePath.includes('tablet'), // tokens that match this filter will be added inside the media query
}]
}
}]
}
}
});The javascript/esm format exports a token dictionary as an es6 export statement.
export default {
colors: {
primary: '#0D70E6',
},
}myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
// ...
"format": "javascript/esm",
}]
}
}
});The typescript/esm-declarations format exports a token dictionary as a typescript declaration file.
export default {
colors: {
primary: string,
},
}myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
// ...
"format": "typescript/esm-declarations",
}]
}
}
});The javascript/commonJs format exports a token dictionary as an commonJs module.
exports.default = {
colors: {
primary: '#0D70E6',
},
}myStyleDictionary.extend({
"platforms": {
"js": {
"transforms": //...,
"files": [{
// ...
"format": "javascript/commonJs",
}]
}
}
});Transforms change the value or name of a token.
You can use transforms by refering the name in the array value of the transformsproperty of a platform.
If you want to use the same transformers multiple times you can create a transform group for easy reference.
myStyleDictionary.registerTransformGroup({
name: 'webHex',
transforms: ['color/hexAlpha', 'dimension/pixelToRem', 'font/css'],
})This packages ships a predefined transform group, called css/extended.
It includes all transforms from the original css transform group as well as the following transforms: color/rgbAlpha, shadow/css, font/css, fontFamily/css, fontWeight/number, name/pathToDotNotation, cubicBezier/css, border/css.
You can use it like any other transform Group:
myStyleDictionary.extend({
platforms: {
css: {
transformGroup: 'css/extended',
files: [
{
// ...
},
],
},
},
})This name transformer replaces the token name with the entire path of the token in dot.notation.
This is especially useful for flat .js or .json files.
To use it simply add name/pathToDotNotation to the transforms array.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['name/pathToDotNotation'],
files: [
{
// ...
},
],
},
},
}){
colors: {
red: {
100: {
// ...
}
}
}
}{
"colors.red.100": {
// ...
}
}This name transformer replaces the token name with the entire path of the token in camelCase notation.
To use it simply add name/pathToCamelCase to the transforms array.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['name/pathToCamelCase'],
files: [
{
// ...
},
],
},
},
}){
colors: {
bg: {
default: {
// ...
}
}
}
}{
"colorsBgDefault": {
// ...
}
}This name transformer replaces the token name with the entire path of the token in camelCase notation.
To use it simply add name/pathToPascalCase to the transforms array.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['name/pathToPascalCase'],
files: [
{
// ...
},
],
},
},
}){
colors: {
bg: {
default: {
// ...
}
}
}
}{
"ColorsBgDefault": {
// ...
}
}This value transformer replaces the value of a token with a $type or type of color with an rgba string. If the token has an alpha value, it will be used as the alpha of the rgba string.
Note: If your initial color value has an alpha value (e.g. hex8) AND you add an alpha property, the alpha property will simply replace the previous alpha value.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['color/rgbAlpha'],
files: [
{
// ...
},
],
},
},
}){
colors: {
blue: {
500: {
value: "#0D70E6",
$type: "color",
alpha: 0.4
}
}
}
}{
colors: {
blue: {
500: {
value: "rgba(13, 112, 230, 0.4)",
$type: "color",
alpha: 0.4
}
}
}
}This value transformer replaces the value of a token with a $type or type of color with a hex string. If the token has an alpha value, it will be used as the alpha of the hex8 string.
Note: If your initial color value has an alpha value (e.g. rgba) AND you add an alpha property, the alpha property will simply replace the previous alpha value.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['color/hexAlpha'],
files: [
{
// ...
},
],
},
},
}){
colors: {
blue: {
500: {
value: "rgba(13, 112, 230, 0.4)",
$type: "color",
alpha: 0.2
}
}
}
}{
colors: {
blue: {
500: {
value: "#0D70E633", // prev alpha value is replaced with 0.2 from alpha property
$type: "color",
alpha: 0.2
}
}
}
}This value transformer replaces the value of a token with a $type or type of color with a hex string.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['color/hex'],
files: [
{
// ...
},
],
},
},
}){
colors: {
blue: {
500: {
value: "rgba(13, 112, 230, 0.4)",
$type: "color"
}
}
}
}{
colors: {
blue: {
500: {
value: "#0D70E666",
$type: "color"
}
}
}
}This value transformer replaces the value of a token with a $type or type of color with an rgba string.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['color/rgba'],
files: [
{
// ...
},
],
},
},
}){
colors: {
blue: {
500: {
value: "#0D70E666",
$type: "color"
}
}
}
}{
colors: {
blue: {
500: {
value: "rgba(13, 112, 230, 0.4)",
$type: "color"
}
}
}
}This value transformer replaces the value of a token with a $type or type of color with an rgba float object.
This is helpful for tools and platforms and use float rgba values where the r, g, b and a values go from 0 to 1. For example when preparing tokens to be imported into Figma.
myStyleDictionary.extend({
platforms: {
json: {
transforms: ['color/rgbaFloat'],
files: [
{
// ...
},
],
},
},
}){
colors: {
blue: {
500: {
value: "#0D70E666",
$type: "color"
}
}
}
}{
colors: {
blue: {
500: {
value: {
r: 0.051,
g: 0.439,
b: 0.902,
a: 0.4
},
$type: "color"
}
}
}
}This value transformer replaces the value of a w3c shadow token with a $type or type of shadow with a css shadow string.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['shadow/css'],
files: [
{
// ...
},
],
},
},
}){
shadow: {
small: {
value: {
"color": "#00000066",
"offsetX": "0px",
"offsetY": "1px",
"blur": "2px",
"spread": "0px"
},
$type: "shadow"
}
}
}{
shadow: {
small: {
value: "0px 1px 2px 0px #00000066",
$type: "shadow"
}
}
}This value transformer replaces the value of a w3c typography token with a $type or type of typography with a css font string.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['font/css'],
files: [
{
// ...
},
],
},
},
}){
typography: {
body: {
value: {
fontWeight: 500,
fontSize: "16px",
lineHeight: "22px",
fontFamily: "Helvetica",
fontStyle: "italic"
},
$type: "typography"
}
}
}{
typography: {
body: {
value: "italic 500 16px/22px Helvetica",
$type: "typography"
}
}
}This value transformer replaces the value of a w3c fontFamily token with a $type or type of fontFamily with a css fontFamily string.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['fontFamily/css'],
files: [
{
// ...
},
],
},
},
}){
fontFamily: {
body: {
value: ['helvetica', 'sans-serif', 'Helvetica Neue'],
$type: "fontFamily"
}
}
}{
fontFamily: {
body: {
value: "helvetica, sans-serif, 'Helvetica Neue'",
$type: "fontFamily"
}
}
}This value transformer replaces the value of a w3c fontWeight token with a $type or type of fontWeight with a css fontWeight number.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['fontWeight/number'],
files: [
{
// ...
},
],
},
},
}){
fontWeight: {
body: {
value: "light",
$type: "fontWeight"
}
}
}{
fontWeight: {
body: {
value: 300,
$type: "fontWeight"
}
}
}This value transformer replaces the value of a w3c gradient token with a $type or type of gradient with a css gradient string.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['gradient/css'],
files: [
{
// ...
},
],
},
},
}){
gradients: {
blueToGreen: {
angle: "45deg"
value: value: [
{
"color": "#288BD2",
"position": 0
},
{
"color": "#28D29F",
"position": 1
}
],
$type: "gradient"
}
}
}{
gradients: {
blueToGreen: {
value: "45deg, #288BD2 0%, #28D29F 100%",
$type: "gradient"
}
}
}This value transformer replaces the value of a w3c cubicBezier token with a $type or type of cubicBezier with a css cubicBezier string.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['cubicBezier/css'],
files: [
{
// ...
},
],
},
},
}){
shadow: {
small: {
value: {
x1: 0.5,
y1: 0,
x2: 1,
y2: 1
},
$type: "cubicBezier"
}
}
}{
shadow: {
small: {
value: "cubic-bezier(0.5, 0, 1, 1)",
$type: "cubicBezier"
}
}
}This value transformer replaces the value of a token with a $type or type of dimension that has a px value, with a rem value.
Supports multiple formats:
- String format:
"32px" - Old structured format:
{ value: "32px" } - New structured format (DTCG spec):
{ value: 32, unit: "px" }
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['dimension/pixelToRem'],
files: [
{
// ...
},
],
options: {
basePxFontSize: 16,
},
},
},
}){
size: {
small: {
value: "32px",
$type: "dimension"
},
medium: {
$value: {
value: "64px"
},
$type: "dimension"
},
large: {
$value: {
value: 96,
unit: "px"
},
$type: "dimension"
}
}
}{
size: {
small: {
value: "2rem",
$type: "dimension"
},
medium: {
$value: "4rem",
$type: "dimension"
},
large: {
$value: "6rem",
$type: "dimension"
}
}
}This value transformer replaces the value of a token with a $type or type of dimension that has a rem value, with a px value.
Supports multiple formats:
- String format:
"2rem" - Old structured format:
{ value: "2rem" } - New structured format (DTCG spec):
{ value: 2, unit: "rem" }
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['dimension/remToPixel'],
files: [
{
// ...
},
],
options: {
basePxFontSize: 16,
},
},
},
}){
size: {
small: {
value: "2rem",
$type: "dimension"
},
medium: {
$value: {
value: "4rem"
},
$type: "dimension"
},
large: {
$value: {
value: 6,
unit: "rem"
},
$type: "dimension"
}
}
}{
size: {
small: {
value: "32px",
$type: "dimension"
},
medium: {
$value: "64px",
$type: "dimension"
},
large: {
$value: "96px",
$type: "dimension"
}
}
}This value transformer replaces the value of a token with a $type or type of dimension that has a rem or px value, with a unitless pixel based value. This is useful for example when preparing tokens to be imported into Figma.
Supports multiple formats:
- String format:
"2rem","32px" - Old structured format:
{ value: "2rem" },{ value: "32px" } - New structured format (DTCG spec):
{ value: 2, unit: "rem" },{ value: 32, unit: "px" }
myStyleDictionary.extend({
platforms: {
json: {
transforms: ['dimension/pixelUnitless'],
files: [
{
// ...
},
],
options: {
basePxFontSize: 16,
},
},
},
})This value transformer replaces the value of a token with a $type or type of clamp that has a $value object with min, ideal and max property, with a css clamp function.
myStyleDictionary.extend({
platforms: {
json: {
transforms: ['clamp/css'],
files: [
{
// ...
},
],
},
},
}){
size: {
small: {
value: {
min: "1.5rem",
ideal: "0.5vw + 0.75rem",
max: "2.5rem"
},
$type: "clamp"
}
}
}{
size: {
small: {
value: "clamp(1.5rem, 0.5vw + 0.75rem, 2.5rem)",
$type: "clamp"
}
}
}Filters are used to filter out unwanted tokens when configuring output files
Only allows tokens that come from a source file to be included in the output. Tokens from an include will be removed.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isSource",
// ...
}]
}
}
});Only allows tokens with a type or $type property of color.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isColor",
// ...
}]
}
}
});Only allows tokens with a type or $type property of gradient.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isGradient",
// ...
}]
}
}
});Only allows tokens with a type or $type property of color or gradient.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isColorOrGradient",
// ...
}]
}
}
});Only allows tokens with a type or $type property of typography.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isTypography",
// ...
}]
}
}
});Only allows tokens with a type or $type property of typography, fontWeight or fontFamily.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isTypographic",
// ...
}]
}
}
});Only allows tokens with a type or $type property of transition.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isTransition",
// ...
}]
}
}
});Only allows tokens with a type or $type property of strokeStyle.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isStrokeStyle",
// ...
}]
}
}
});Only allows tokens with a type or $type property of shadow.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isShadow",
// ...
}]
}
}
});Only allows tokens with a type or $type property of fontWeight.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isFontWeight",
// ...
}]
}
}
});Only allows tokens with a type or $type property of fontFamily.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isFontFamily",
// ...
}]
}
}
});Only allows tokens with a type or $type property of duration.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isDuration",
// ...
}]
}
}
});Only allows tokens with a type or $type property of dimension.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isDimension",
// ...
}]
}
}
});Only allows tokens with a type or $type property of cubicBezier.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isCubicBezier",
// ...
}]
}
}
});Only allows tokens with a type or $type property of border.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isBorder",
// ...
}]
}
}
});Only allows tokens with a type or $type property of clamp and an object as the $value with a min, ideal and max property.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isClamp",
// ...
}]
}
}
});The getHasAttribute function returns a filter function that filters by one or multiple properties.
You can provide one or multiple arguments that are used to check of the token has at least one of those properties.
{
color: {
red: {
$value: 'red',
deprecated: true // e.g. check that a deprecated attribute exists
}
}
}import StyleDictionary from 'style-dictionary-utils'
import {getHasAttribute} from 'style-dictionary-utils/filter/getHasAttribute.js'
StyleDictionary.registerFilter({
name: 'shouldAvoid',
matcher: getHasAttribute('deprecated', 'removed'),
})import StyleDictionary from 'style-dictionary-utils'
import {getHasAttribute} from 'style-dictionary-utils/filter/getHasAttribute.js'
myStyleDictionary.extend({
"platforms": {
"deprecatedJson": {
"transforms": //...,
"files": [{
"filter": getHasAttribute('deprecated','removed'), // allows only tokens with a `deprecated` or `removed propery, e.g. if you want` to create a json with tokens not to use.
// ...
}]
}
}
});The getHasAttributeValue function returns a filter function that filters by one or multiple properties that have a specific value.
You can provide a string or array of strings for the first argument, to define which properties should be checked.
Similarily you can provide one value or an array of values for the second argument, to define which values to check against. Note: If you provide an array of values every property can have either of those values.
getHasAttributeValue(attributes: string[], values: any[]){
color: {
red: {
$value: 'red',
deprecated: true // e.g. check that a deprecated value exists and is `true`
}
}
}import StyleDictionary from 'style-dictionary-utils'
import {getHasAttributeValue} from 'style-dictionary-utils/filter/getHasAttributeValue.js'
StyleDictionary.registerFilter({
name: 'isDeprecated',
matcher: getHasAttributeValue('deprecated', true),
})import StyleDictionary from 'style-dictionary-utils'
import {getHasAttributeValue} from 'style-dictionary-utils/filter/getHasAttributeValue.js'
myStyleDictionary.extend({
"platforms": {
"deprecatedJson": {
"transforms": //...,
"files": [{
"filter": getHasAttributeValue('deprecated',true), // allows only tokens with a `deprecated` property that is true
// ...
}]
}
}
});The getIsType function returns a filter function that filters by one or multiple types.
You can provide one or multiple arguments that are used as types to filter against the type or $type property.
import StyleDictionary from 'style-dictionary-utils'
import {getIsType} from 'style-dictionary-utils/filter/getIsType.js'
StyleDictionary.registerFilter({
name: 'isAnimation',
matcher: getIsType('duration', 'transition', 'cubicBezier'),
})import StyleDictionary from 'style-dictionary-utils'
import {getIsType} from 'style-dictionary-utils/filter/getIsType.js'
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": getIsType('size','dimension'), // allows only tokens with type `size` or `dimension`
// ...
}]
}
}
});