Skip to main content

Getting Started

Load the 3.0.0-beta colour tokens and use the same semantic names in Figma, CSS and TypeScript.

Version: Beta

Colour tokens have one semantic name across design and code. Start by loading the beta token bundle, then bind components to the names documented here.

Load the CSS tokens​

Install the beta package:

pnpm add @equinor/eds-tokens@beta

Import the bundled variables once in your application:

@import '@equinor/eds-tokens/next/css/variables.css';

The bundle includes the semantic colours for both light and dark. Components then use CSS custom properties:

.button--primary {
background: var(--eds-background-interactive-accent-emphasis-default);
color: var(--eds-text-on-emphasis-accent);
}
The next path is temporary

The 3.0.0 beta publishes the new output under next/* while legacy and new components coexist. The prefix will be removed before the stable release. The token names remain the same.

Reading a token name​

A name answers five questions, from left to right:

SurfaceBehaviourToneLevelState
backgroundinteractiveaccentemphasishover
SegmentQuestionExample
SurfaceWhat am I colouring?background, border, text, icon
BehaviourCan the user act on it?interactive, non-interactive
ToneWhat does it mean?accent, neutral, danger
LevelHow visually strong is it?muted, emphasis, and either default or selected, depending on surface and behaviour
StateWhat is happening now?default, hover, pressed

Not every name contains all five segments. Non-interactive colours have no state, and families such as text.primary and background.surface name a specific role directly.

Usage explains how to choose the branch, tone, level and state.

One name in Figma, CSS and TypeScript​

Each colour token has one name in Figma, one CSS custom property and one TypeScript path:

WhereHow it is written
Figmabackground.non-interactive.accent.muted
CSS--eds-background-non-interactive-accent-muted
TypeScriptsemantic.background.nonInteractive.accent.muted

CSS is --eds- followed by the dotted name with hyphens for dots. TypeScript uses the dotted name with each segment camel-cased.

The token reference is the authority for CSS names. The CSS name and Figma name are carried by the token definition rather than derived from each other, so if the pattern and reference ever disagree, the reference is right.

Need a colour value?

Look up the token instead of copying a hex value. A hardcoded value will not follow the colour scheme, and nothing will tell you when it stops matching the token it came from.

Switching colour scheme​

The system reads the data-color-scheme attribute. Light is the default, so a page without the attribute is light:

<!-- Light, the default -->
<html data-color-scheme="light"></html>

<!-- Dark -->
<html data-color-scheme="dark"></html>

Set it once, at the top of the page or application, so the whole interface switches together.

The attribute can be set on any ancestor and it cascades, so scoping a single panel to dark inside a light page is technically possible. We do not recommend it. A colour scheme describes the interface, not a region inside it.

Using the tokens in TypeScript​

The tokens also ship as TypeScript objects for places a CSS custom property cannot reach, such as a chart library, canvas, email template or React Native surface.

import { semantic } from '@equinor/eds-tokens/next/ts/semantic/light'

semantic.background.interactive.accent.emphasis.default // '#21767e'

Each module is imported directly; there is no barrel. The objects are as const, and each one also exports its type, so Semantic gives you autocompletion and a compile error on a name that does not exist.

The colour scheme does not switch for you

In CSS you write one name and the data-color-scheme attribute decides the value. In TypeScript there is no attribute to read: semantic/light and semantic/dark are separate objects, and you choose which one to use.

import { semantic as light } from '@equinor/eds-tokens/next/ts/semantic/light'
import { semantic as dark } from '@equinor/eds-tokens/next/ts/semantic/dark'

const tokens = prefersDark ? dark : light

Prefer CSS custom properties wherever they work. Reach for the TypeScript objects only where they do not, and expect to handle the scheme yourself.

Values are hex rather than the OKLCH used by the CSS output. They are generated from the same source, so they agree, but a value copied from TypeScript does not carry the CSS output's wide-gamut precision.

From next/ts/, import semantic. The other modules (colorScheme, colors, font, elevation and primitives) hold the layers that semantic is resolved from. They are internal and can be renamed or restructured in any release. The palette explains the colour layers as concepts.

density is a temporary exception. semantic carries the Comfortable values for spacing, corner radius and typography, so an app in another density imports those groups from density/compact or density/relaxed instead. The exception lasts until the TypeScript output ships one file per colour scheme and density.

For designers​

Add the EDS colour library to your Figma file and choose variables by semantic name. The names are identical to the ones above, so a design and its implementation refer to the same role.

Only the semantic layer is published to the variable picker. The numbered scale underneath it is hidden, so a raw palette value cannot be bound to a component by accident.

How variable scopes filter the picker​

Each variable has scopes that decide which pickers in Figma offer it. The scopes are a general guideline that steers each picker towards the property a token is usually used on. Background tokens are offered for the fill of a frame or shape, border tokens for strokes, and text tokens for the fill of a text layer, so the list you open is already narrowed to the usual choices.

The scopes do not define which tokens are allowed on which property. Some tokens are offered in more than one picker on purpose:

  • background.surface is also offered for strokes, because some places in Figma need a stroke in the surface colour.
  • The spacing variables are also offered for width and height, because icons are sized with them. Button binds the width and height of its icon to spacing.lg.

If a token is missing from a picker, it is usually meant for a different property.

Next step​

Usage shows how to choose levels and states, pair foregrounds and apply the tokens to common interface patterns.