CSS Token provides a set of design tokens
and utilities that enable a standardized system to specify colors, sizes, shadows,
and other design-related values in your app.
Minimal : No build step, easily use with inline styles via
CSS Hooks 1 .
Flexible : Static and dynamic tokens for custom use cases.
SSR-safe : Tokens work on the server and client.
Strongly typed : Tokens can be narrowly typed to prevent invalid values.
1 CSS Hooks is a refreshingly light styling
solution that lets you to “hook” into CSS features like :hover
and media
queries directly from the style
prop. With minimal overhead, you enjoy the
benefits of local reasoning, reusing your existing knowledge of standard CSS,
strong typing, while being SSR-safe.
npm i css-token
To get started, import the reset and tokens in a globals.css
(or equivalent)
file. The reset ensures a consistent baseline to start from with better
defaults.
@import " css-token/reset.css " ;
@import " css-token/all.css " ;
Then, use the CSS variables in your components:
import " ./globals.css " ;
function App () {
return (
< div
style ={ {
display : " inline-block " ,
backgroundColor : " var(--lime-2) " ,
color : " var(--lime-10) " ,
borderRadius : " var(--rounded-md) " ,
padding : " var(--length-10) " ,
} }
>
Hello world
</ div >
);
}
Tokens have a static and dynamic variant, both of which are SSR-compatible.
Static tokens are imported in your globals.css
file and available as CSS
variables — they are not tree-shakeable, but have zero runtime cost.
Dynamic tokens are computed at runtime, and whose values are therefore
tree-shakeable, but have a runtime cost (on-demand calculations).
For autocomplete and typesafety of static tokens, createToken
generates a
token function based on the tokens you imported in your globals CSS file.
This is the simplest way to get started:
@import " css-token/reset.css " ;
@import " css-token/all.css " ;
import { createToken } from " css-token " ;
const token = createToken ();
token ( " rounded-md " ); // ok, all tokens available
All tokens weigh ~8kB gzipped combined, but you can import them separately to
minimize size, seen below.
Since there’s no build step, there’s no “just in time” on-demand static
compilation of tokens. To import a subset of tokens to minimize size, you can
@import
them each separately:
@import " css-token/reset.css " ;
@import " css-token/ color .css " ;
@import " css-token/ shadow .css " ;
import { createToken } from " css-token " ;
const token = createToken ([ " color " , " shadow " ]);
token ( " rounded-md " ); // not allowed
Play on CodeSandbox .
import { createToken } from " css-token " ;
const token = createToken (); // all tokens typed
function App () {
return (
< div
style ={ {
display : " inline-block " ,
backgroundColor : token ( " blue-4 " ),
color : token ( " blue-14 " ),
borderRadius : token ( " rounded-md " ),
padding : token ( " length-10 " ),
} }
>
Hello World
</ div >
);
}
The above produces:
Hello World
@import " css-token/color.css " ;
A color scale using oklch
for HD colors, converted to rgb
for SD colors.
Demo You are viewing this on a non-HD color display (sRGB) You are viewing this on a HD color display (p3)
Grays stone 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
gray 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
slate 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mauve 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Metals bronze 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
gold 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
emerald 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sapphire 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
amethyst 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Colors red 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
orange 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
amber 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
yellow 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
lime 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
grass 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
green 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
teal 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mint 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cyan 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sky 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
blue 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
indigo 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
purple 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
magenta 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
pink 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
crimson 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
To minimize size, prefer importing only the colors you need:
@import " css-token/mauve.css " ;
@import " css-token/red.css " ;
@import " css-token/yellow.css " ;
@import " css-token/green.css " ;
@import " css-token/blue.css " ;
@import " css-token/purple.css " ;
const token = createToken ([
" mauve " ,
" red " ,
" yellow " ,
" green " ,
" blue " ,
" purple " ,
]);
Available as static tokens from the global CSS file:
< div
style ={ {
backgroundColor : token ( " red-2 " ), // var(--red-2)
color : token ( " red-10 " ), // var(--red-10)
} }
/>
@import " css-token/color-p3.css " ;
/* or, import separately */
@import " css-token/red-p3.css " ;
@import " css-token/yellow-p3.css " ;
Default colors are within sRGB. To get a HD color within the p3 color space,
prepend p3_
:
token ( " p3_red-10 " );
With a fallback using CSS Hooks:
const [ hooks , css ] = createHooks ({
" &:p3 " : " @media (color-gamut: p3) " ,
});
< div
style ={ css ({
backgroundColor : token ( " red-2 " ),
color : token ( " red-10 " ),
" &:p3 " : {
backgroundColor : token ( " p3_red-2 " ),
color : token ( " p3_red-10 " ),
},
}) }
/>
The color ()
token function lets you select a color on-demand, which is
useful to adjust the opacity and vibrance at will:
import { color } from " css-token " ;
color ( " sky-8 " ); // default
color ( " sky-8 " , { alpha : 0.5 }); // 50% opacity
color ( " sky-8 " , { vibrance : 0.5 }); // 50% chroma
It’s recommended you extract dynamic tokens outside of components, so they’re
only calculated once:
export const lime10_50 = color ( " lime-10 " , { alpha : 0.5 });
@import " css-token/shadow.css " ;
Shadows are defined by their preset, elevation, color, and strength.
Shadow presets are pre-defined shadows available as CSS variables:
Demo
< div
style ={ {
boxShadow : token ( " shadow " ),
} }
/>
token ( " shadow " ); // default
token ( " shadow-sharp " );
token ( " shadow-dreamy " );
token ( " shadow-long " );
Shadows can be elevated:
Demo none-1
dreamy-1
sharp-1
long-1
none-2
dreamy-2
sharp-2
long-2
none-3
dreamy-3
sharp-3
long-3
none-4
dreamy-4
sharp-4
long-4
< div
style ={ {
boxShadow : token ( " shadow-4 " ),
} }
/>
token ( " shadow-sharp-3 " );
token ( " shadow-dreamy-2 " );
token ( " shadow-long-4 " );
Colored shadows and shadows with a custom intensity can be generated on-demand
using the shadow ()
token:
Demo
import { shadow } from " css-token " ;
const customLimeShadow = shadow ({
preset : " long " ,
elevation : 2 ,
// on-demand only options
color : " lime-10 " ,
intensity : 1.5 ,
});
< div
style ={ {
boxShadow : customLimeShadow ,
} }
/>
@import " css-token/text.css " ;
Text is defined by its family, size, weight, tracking, and leading.
< div
style ={ {
fontFamily : token ( " font-mono " ),
fontSize : token ( " font-size-2xl " ),
fontWeight : token ( " font-weight-thin " ),
letterSpacing : token ( " tracking-tight " ),
lineHeight : token ( " leading-tight " ),
} }
>
Text token example
</ div >
Demo
Three system font families are available:
< div
style ={ {
// mono, sans, serif
fontFamily : token ( " font-mono " ),
} }
/>
Scale 1
through 16
or 5xs
through 5xl
.
< div
style ={ {
// 1-16
fontSize : token ( " font-size-10 " ),
// 5xs, 4xs, 3xs, 2xs, xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl
fontSize : token ( " font-size-2xl " ),
} }
/>
The fontSize ()
token function defaults to rem
, but can be overridden:
import { fontSize } from " css-token " ;
< div
style ={ {
fontSize : fontSize ( 10 ), // rem
fontSize : fontSize ( 7 , " em " ),
fontSize : fontSize ( 4 , " px " ),
} }
/>
If you need a unitless scale inside a CSS file to convert to em
:
@import " css-token/font-size-scale.css " ;
div {
font-size : calc ( var ( --font-size-scale-10 ) * 1 em );
}
Scale 1
through 9
or hairline
through black
.
< div
style ={ {
// 1-9
fontWeight : token ( " font-weight-5 " ),
// hairline, thin, light, normal, medium, semibold,
// bold, extrabold, black
fontSize : token ( " font-weight-medium " ),
} }
/>
Refers to the letter spacing. Scale 1
through 9
or tight
through loose
.
< div
style ={ {
// 1-9
letterSpacing : token ( " tracking-5 " ),
// tight, snug, normal, relaxed, loose
letterSpacing : token ( " tracking-loose " ),
} }
/>
Refers to the line height. Scale 1
through 9
or tight
through loose
.
< div
style ={ {
// 1-9
lineHeight : token ( " leading-5 " ),
// tight, snug, normal, relaxed, loose
lineHeight : token ( " leading-loose " ),
} }
/>
Scale from 1
through 32
.
< div
style ={ {
width : token ( " length-10 " ),
} }
/>
The length ()
token function allows you to specify a unit:
import { length } from " css-token " ;
< div
style ={ {
width : length ( 10 ), // rem
height : length ( 7 , " em " ),
padding : length ( 4 , " px " ),
} }
/>
If you need a unitless scale inside a CSS file to convert to em
:
@import " css-token/length-scale.css " ;
div {
width : calc ( var ( --length-scale-10 ) * 1 em );
}
Demo 0.5
1
1.5
2
2.5
3
3.5
4
4.5
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Specifies corner rounding.
@import " css-token/rounded.css " ;
< div
style ={ {
// xs, sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, full
borderRadius : token ( " rounded-md " ),
} }
/>
Demo xs
sm
md
lg
xl
2xl
3xl
4xl
5xl
full
@import " css-token/spring.css " ;
Motion is defined by springs.
< div
style ={ {
// Default:
transition : ` transform ${ token ( " spring " ) }` ,
// Other presets:
transition : ` transform ${ token ( " spring-wobbly " ) }` ,
transition : ` transform ${ token ( " spring-wobbly-2 " ) }` ,
transition : ` transform ${ token ( " spring-stiff " ) }` ,
transition : ` transform ${ token ( " spring-stiff-2 " ) }` ,
} }
/>
Demo default
wobbly
wobbly-2
stiff
stiff-2
The spring ()
token function lets you select a spring on-demand, which is
useful to adjust the stiffness and damping at will:
import { spring } from " css-token " ;
spring (); // default
spring ({ stiffness : 100 , damping : 20 });
Specifies the stacking order of layers.
@import " css-token/layer.css " ;
< div
style ={ {
// 1-5 + 'max'
zIndex : token ( " layer-1 " ),
} }
/>
There’s also a layer ()
token function:
import { layer } from " css-token " ;
layer ( 1 );
layer ( " max " );
Text gradient utility for text.
import { textGradient } from " css-token " ;
const redToBlueTextGradient = textGradient ({
stops : [ token ( " red-5 " ), token ( " blue-8 " )],
// options:
colorSpace : " oklch " , // e.g. "srgb" NOTE: no Firefox support
direction : " 90deg " , // e.g. "to bottom"
});
< div style ={ redToBlueTextGradient } > Hello World </ div >
Demo
@import " css-token/prose.css " ;
Note: This depends on text.css
and length.css
. Ensure they’ve been imported.
To style free-form prose elements containing arbitrary HTML (e.g. Markdown), you
can use the prose
class to apply styles to the appropriate elements:
< article className = " prose " >
{ /* Generated from markdown */ }
< h1 > Heading </ h1 >
< p > Paragraph </ p >
</ article >
While inline styles should be preferred wherever possible with CSS Hooks, if you
need to define global styles, use the global.css
stylesheet with the CSS
variables.
For example, pseudo elements, descendant selectors, or keyframes require global
styles:
. container span :: before {
content : "" ;
display : block ;
width : var ( --length-8 );
height : var ( --length-8 );
}
@keyframes spin {
0% {
transform : rotate ( 0 deg );
}
100% {
transform : rotate ( 360 deg );
}
}
If you need runtime global styles because a runtime token is a dependency, you
can use the global
function. Global styles are defined by their selector to
scope the styles, and a style object.
import { global } from " css-token " ;
import { limeShadow } from " ./tokens " ;
const containerSelector = " :root " ;
const styles = {
" code [data-line] " : { boxShadow : limeShadow },
};
const rawCss = global ( containerSelector , styles );
< style dangerouslySetInnerHTML ={ { __html : rawCss } } />