Awesome
Style dictionary utils
style-dictionary-utils
is a collection of filters
, transformers
and formats
for Style Dictionary that make working with w3c design tokens a lot easier.
Installation
Install the style-dictionary-utils
as well as style-dictionary
.
npm i -D style-dictionary-utils style-dictionary
How to use style dictionary version 3?
If 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.
Getting started
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<sup>*</sup> are available to you via the keys mentioned in the docs below.
Extending style dictionary
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.
Included utilities
- Formats
- Transformers
- Filters
- Special Filter
📑 Formats
css/advanced
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
.
selector
is a string that is wrapped around your css. If theselector
is undefined, the default selector or one define atfile.options.selector
will be used. If you don't want a selector, set it tofalse
.atRule
can be a string or array of strings, that are wrapped around the css andselector
with the first being the outer layer.matcher
is 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;
}
}
Usage:
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
}]
}
}]
}
}
});
javascript/esm
The javascript/esm
format exports a token dictionary as an es6 export
statement.
export default {
colors: {
primary: '#0D70E6',
},
}
Usage:
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
// ...
"format": "javascript/esm",
}]
}
}
});
typescript/esm-declarations
The typescript/esm-declarations
format exports a token dictionary as a typescript
declaration file.
export default {
colors: {
primary: string,
},
}
Usage:
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
// ...
"format": "typescript/esm-declarations",
}]
}
}
});
javascript/commonJs
The javascript/commonJs
format exports a token dictionary as an commonJs module
.
exports.default = {
colors: {
primary: '#0D70E6',
},
}
Usage:
myStyleDictionary.extend({
"platforms": {
"js": {
"transforms": //...,
"files": [{
// ...
"format": "javascript/commonJs",
}]
}
}
});
🤖 Transformers
Transforms change the value
or name
of a token.
You can use transforms by refering the name in the array value of the transforms
property of a platform
.
Transform group
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'],
})
css/extended
transform group
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: [
{
// ...
},
],
},
},
})
name/pathToDotNotation
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: [
{
// ...
},
],
},
},
})
Before transformation
{
colors: {
red: {
100: {
// ...
}
}
}
}
After transformation
{
"colors.red.100": {
// ...
}
}
name/pathToCamelCase
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: [
{
// ...
},
],
},
},
})
Before transformation
{
colors: {
bg: {
default: {
// ...
}
}
}
}
After transformation
{
"colorsBgDefault": {
// ...
}
}
name/pathToPascalCase
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: [
{
// ...
},
],
},
},
})
Before transformation
{
colors: {
bg: {
default: {
// ...
}
}
}
}
After transformation
{
"ColorsBgDefault": {
// ...
}
}
color/rgbAlpha
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: [
{
// ...
},
],
},
},
})
Before transformation
{
colors: {
blue: {
500: {
value: "#0D70E6",
$type: "color",
alpha: 0.4
}
}
}
}
After transformation
{
colors: {
blue: {
500: {
value: "rgba(13, 112, 230, 0.4)",
$type: "color",
alpha: 0.4
}
}
}
}
color/hexAlpha
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: [
{
// ...
},
],
},
},
})
Before transformation
{
colors: {
blue: {
500: {
value: "rgba(13, 112, 230, 0.4)",
$type: "color",
alpha: 0.2
}
}
}
}
After transformation
{
colors: {
blue: {
500: {
value: "#0D70E633", // prev alpha value is replaced with 0.2 from alpha property
$type: "color",
alpha: 0.2
}
}
}
}
color/hex
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: [
{
// ...
},
],
},
},
})
Before transformation
{
colors: {
blue: {
500: {
value: "rgba(13, 112, 230, 0.4)",
$type: "color"
}
}
}
}
After transformation
{
colors: {
blue: {
500: {
value: "#0D70E666",
$type: "color"
}
}
}
}
color/rgba
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: [
{
// ...
},
],
},
},
})
Before transformation
{
colors: {
blue: {
500: {
value: "#0D70E666",
$type: "color"
}
}
}
}
After transformation
{
colors: {
blue: {
500: {
value: "rgba(13, 112, 230, 0.4)",
$type: "color"
}
}
}
}
color/rgbaFloat
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: [
{
// ...
},
],
},
},
})
Before transformation
{
colors: {
blue: {
500: {
value: "#0D70E666",
$type: "color"
}
}
}
}
After transformation
{
colors: {
blue: {
500: {
value: {
r: 0.051,
g: 0.439,
b: 0.902,
a: 0.4
},
$type: "color"
}
}
}
}
shadow/css
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: [
{
// ...
},
],
},
},
})
Before transformation
{
shadow: {
small: {
value: {
"color": "#00000066",
"offsetX": "0px",
"offsetY": "1px",
"blur": "2px",
"spread": "0px"
},
$type: "shadow"
}
}
}
After transformation
{
shadow: {
small: {
value: "0px 1px 2px 0px #00000066",
$type: "shadow"
}
}
}
font/css
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: [
{
// ...
},
],
},
},
})
Before transformation
{
typography: {
body: {
value: {
fontWeight: 500,
fontSize: "16px",
lineHeight: "22px",
fontFamily: "Helvetica",
fontStyle: "italic"
},
$type: "typography"
}
}
}
After transformation
{
typography: {
body: {
value: "italic 500 16px/22px Helvetica",
$type: "typography"
}
}
}
fontFamily/css
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: [
{
// ...
},
],
},
},
})
Before transformation
{
fontFamily: {
body: {
value: ['helvetica', 'sans-serif', 'Helvetica Neue'],
$type: "fontFamily"
}
}
}
After transformation
{
fontFamily: {
body: {
value: "helvetica, sans-serif, 'Helvetica Neue'",
$type: "fontFamily"
}
}
}
fontWeight/number
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: [
{
// ...
},
],
},
},
})
Before transformation
{
fontWeight: {
body: {
value: "light",
$type: "fontWeight"
}
}
}
After transformation
{
fontWeight: {
body: {
value: 300,
$type: "fontWeight"
}
}
}
gradient/css
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: [
{
// ...
},
],
},
},
})
Before transformation
{
gradients: {
blueToGreen: {
angle: "45deg"
value: value: [
{
"color": "#288BD2",
"position": 0
},
{
"color": "#28D29F",
"position": 1
}
],
$type: "gradient"
}
}
}
After transformation
{
gradients: {
blueToGreen: {
value: "45deg, #288BD2 0%, #28D29F 100%",
$type: "gradient"
}
}
}
cubicBezier/css
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: [
{
// ...
},
],
},
},
})
Before transformation
{
shadow: {
small: {
value: {
x1: 0.5,
y1: 0,
x2: 1,
y2: 1
},
$type: "cubicBezier"
}
}
}
After transformation
{
shadow: {
small: {
value: "cubic-bezier(0.5, 0, 1, 1)",
$type: "cubicBezier"
}
}
}
dimension/pixelToRem
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.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['dimension/pixelToRem'],
files: [
{
// ...
},
],
options: {
basePxFontSize: 16,
},
},
},
})
Before transformation
{
size: {
small: {
value: "32px",
$type: "dimension"
}
}
}
After transformation
{
size: {
small: {
value: "2rem",
$type: "dimension"
}
}
}
dimension/remToPixel
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.
myStyleDictionary.extend({
platforms: {
ts: {
transforms: ['dimension/remToPixel'],
files: [
{
// ...
},
],
options: {
basePxFontSize: 16,
},
},
},
})
Before transformation
{
size: {
small: {
value: "2rem",
$type: "dimension"
}
}
}
After transformation
{
size: {
small: {
value: "32px",
$type: "dimension"
}
}
}
dimension/pixelUnitless
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.
myStyleDictionary.extend({
platforms: {
json: {
transforms: ['dimension/pixelUnitless'],
files: [
{
// ...
},
],
options: {
basePxFontSize: 16,
},
},
},
})
clamp/css
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: [
{
// ...
},
],
},
},
})
Before transformation
{
size: {
small: {
value: {
min: "1.5rem",
ideal: "0.5vw + 0.75rem",
max: "2.5rem"
},
$type: "clamp"
}
}
}
After transformation
{
size: {
small: {
value: "clamp(1.5rem, 0.5vw + 0.75rem, 2.5rem)",
$type: "clamp"
}
}
}
🚦 Filters
Filters are used to filter out unwanted tokens when configuring output files
isSource
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",
// ...
}]
}
}
});
isColor
Only allows tokens with a type
or $type
property of color
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isColor",
// ...
}]
}
}
});
isGradient
Only allows tokens with a type
or $type
property of gradient
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isGradient",
// ...
}]
}
}
});
isColorOrGradient
Only allows tokens with a type
or $type
property of color
or gradient
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isColorOrGradient",
// ...
}]
}
}
});
isTypography
Only allows tokens with a type
or $type
property of typography
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isTypography",
// ...
}]
}
}
});
isTypographic
Only allows tokens with a type
or $type
property of typography
, fontWeight
or fontFamily
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isTypographic",
// ...
}]
}
}
});
isTransition
Only allows tokens with a type
or $type
property of transition
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isTransition",
// ...
}]
}
}
});
isStrokeStyle
Only allows tokens with a type
or $type
property of strokeStyle
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isStrokeStyle",
// ...
}]
}
}
});
isShadow
Only allows tokens with a type
or $type
property of shadow
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isShadow",
// ...
}]
}
}
});
isFontWeight
Only allows tokens with a type
or $type
property of fontWeight
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isFontWeight",
// ...
}]
}
}
});
isFontFamily
Only allows tokens with a type
or $type
property of fontFamily
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isFontFamily",
// ...
}]
}
}
});
isDuration
Only allows tokens with a type
or $type
property of duration
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isDuration",
// ...
}]
}
}
});
isDimension
Only allows tokens with a type
or $type
property of dimension
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isDimension",
// ...
}]
}
}
});
isCubicBezier
Only allows tokens with a type
or $type
property of cubicBezier
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isCubicBezier",
// ...
}]
}
}
});
isBorder
Only allows tokens with a type
or $type
property of border
.
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": "isBorder",
// ...
}]
}
}
});
isClamp
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",
// ...
}]
}
}
});
🚦 Special Filter
getHasAttribute
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
}
}
}
Register as a new filter
import StyleDictionary from 'style-dictionary-utils'
import {getHasAttribute} from 'style-dictionary-utils/dist/filter/getHasAttribute'
StyleDictionary.registerFilter({
name: 'shouldAvoid',
matcher: getHasAttribute('deprecated', 'removed'),
})
Use directly in platform
import StyleDictionary from 'style-dictionary-utils'
import {getHasAttribute} from 'style-dictionary-utils/dist/filter/getHasAttribute'
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.
// ...
}]
}
}
});
getHasAttributeValue
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 string
s 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`
}
}
}
Register as a new filter
import StyleDictionary from 'style-dictionary-utils'
import {getHasAttributeValue} from 'style-dictionary-utils/dist/filter/getHasAttributeValue'
StyleDictionary.registerFilter({
name: 'isDeprecated',
matcher: getHasAttributeValue('deprecated', true),
})
Use directly in platform
import StyleDictionary from 'style-dictionary-utils'
import {getHasAttributeValue} from 'style-dictionary-utils/dist/filter/getHasAttributeValue'
myStyleDictionary.extend({
"platforms": {
"deprecatedJson": {
"transforms": //...,
"files": [{
"filter": getHasAttributeValue('deprecated',true), // allows only tokens with a `deprecated` property that is true
// ...
}]
}
}
});
getIsType
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.
Register as a new filter
import StyleDictionary from 'style-dictionary-utils'
import {getIsType} from 'style-dictionary-utils/dist/filter/getIsType'
StyleDictionary.registerFilter({
name: 'isAnimation',
matcher: getIsType('duration', 'transition', 'cubicBezier'),
})
Use directly in platform
import StyleDictionary from 'style-dictionary-utils'
import {getIsType} from 'style-dictionary-utils/dist/filter/getIsType'
myStyleDictionary.extend({
"platforms": {
"ts": {
"transforms": //...,
"files": [{
"filter": getIsType('size','dimension'), // allows only tokens with type `size` or `dimension`
// ...
}]
}
}
});