css-token

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.

1CSS 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.


Table of Contents


Install

npm i css-token

Usage

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

Tokens have a static and dynamic variant, both of which are SSR-compatible.

Autocomplete

For autocomplete and typesafety of static tokens, createToken generates a token function based on the tokens you imported in your globals CSS file.

All Static Tokens

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.

Static Tokens Subset

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

Example

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

Color

@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",
]);

Static Colors

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)
  }}
/>

HD Colors

@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"),
    },
  })}
/>

Dynamic Colors

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 });

Shadow

@import "css-token/shadow.css";

Shadows are defined by their preset, elevation, color, and strength.

Shadow Presets

Shadow presets are pre-defined shadows available as CSS variables:

Demo
none
dreamy
sharp
long
<div
  style={{
    boxShadow: token("shadow"),
  }}
/>
token("shadow"); // default
token("shadow-sharp");
token("shadow-dreamy");
token("shadow-long");

Shadow Elevation

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");

Dynamic Shadows

Colored shadows and shadows with a custom intensity can be generated on-demand using the shadow() token:

Demo
red
yellow
lime
blue
purple
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,
  }}
/>

Text

@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
Text token example

Family

Three system font families are available:

<div
  style={{
    // mono, sans, serif
    fontFamily: token("font-mono"),
  }}
/>

Size

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"),
  }}
/>

Unitless scale

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) * 1em);
}

Weight

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"),
  }}
/>

Tracking

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"),
  }}
/>

Leading

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"),
  }}
/>

Length

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"),
  }}
/>

Unitless scale

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) * 1em);
}
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

Rounded

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

Spring

@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

Dynamic Springs

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 });

Layer (z-index)

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

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
Hello World

Prose

@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>

Globals

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(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

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 }} />