Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import "@equinor/eds-tokens/css/variables-dynamic.css";
import "@equinor/eds-tokens/css/variables";
import { Chip } from "./Chip";

import styles from "./styles.module.css";
Expand Down
15 changes: 13 additions & 2 deletions packages/eds-tailwind/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,28 @@ Tailwind CSS theme for Equinor Design System (EDS).

This package exposes the EDS theme tokens and Tailwind `@theme` declarations as plain CSS. Import it from your app-level stylesheet so Tailwind v4 can process the directives.

## Installation

```sh
pnpm add @equinor/eds-tailwind @equinor/eds-tokens
```

## Usage

1. Ensure Tailwind v4 is configured in your app and that `@import "tailwindcss";` exists in your global stylesheet.
2. Import the theme after Tailwind (order does not strictly matter, but keeping them together is convenient):
2. Import the EDS tokens CSS variables **before** the EDS Tailwind theme:

```css
@import 'tailwindcss';
@import '@equinor/eds-tokens/css/variables';
@import '@equinor/eds-tailwind';
```

The package also imports `@equinor/eds-tokens/css/variables-static.css` to make the CSS variables available.
:::note

The `@equinor/eds-tokens/css/variables` import is required as it provides the CSS custom properties that the theme references. Importing it separately gives you control over where tokens are loaded and prevents duplicate imports if you're already using EDS tokens elsewhere in your application.

:::

## Demo

Expand Down
12 changes: 8 additions & 4 deletions packages/eds-tailwind/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,21 @@
"default": "./theme.css",
"import": "./theme.css"
},
"./theme.css": "./theme.css"
"./theme.css": "./theme.css",
"./theme": {
"style": "./theme.css",
"default": "./theme.css",
"import": "./theme.css"
}
},
"sideEffects": [
"**/*.css"
],
"peerDependencies": {
"@equinor/eds-tokens": ">=1.0.0",
"tailwindcss": ">=4.0.0 <5"
},
"dependencies": {
"@equinor/eds-tokens": "workspace:*"
},
"dependencies": {},
"devDependencies": {
"@tailwindcss/vite": "^4.1.13",
"tailwindcss": "^4.1.13",
Expand Down
3 changes: 2 additions & 1 deletion packages/eds-tailwind/style.css
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
@import 'tailwindcss';
@import './theme.css';
@import '@equinor/eds-tokens/css/variables';
@import '@equinor/eds-tailwind';
2 changes: 0 additions & 2 deletions packages/eds-tailwind/theme.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
@import '@equinor/eds-tokens/css/variables-static';

/* Provide dark variant selector used by the theme */
@custom-variant dark (&:where([data-color-scheme=dark], [data-color-scheme=dark] *));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ async function buildColorsFromConfig(cfg: TokenConfig) {
const PREFIX = tokenConfig.variablePrefix ?? 'x'
const COLOR_PREFIX = PREFIX + '-color' // e.g. "x-color"

// Build static semantic tokens with light theme values and CSS variable references
const semanticColors = _extend({
source: [SEMANTIC_COLORS],
include: [LIGHT_COLORS, LIGHT_SCHEME], // use one scheme to resolve references
Expand All @@ -69,6 +70,41 @@ async function buildColorsFromConfig(cfg: TokenConfig) {
})

await semanticColors.buildAllPlatforms()

// Build semantic color scheme tokens with resolved light/dark values
const DARK_COLORS = path.join(TOKEN_BASE, 'Color Dark.Mode 1.json')
const DARK_SCHEME = path.join(TOKEN_BASE, `${SCHEME_TOKENS_PREFIX}.Dark.json`)
const SCHEME_BUILD_PATH = path.posix.join(
tokenConfig.buildPath ?? 'color/',
'color-scheme/',
)

const lightSemanticColors = _extend({
source: [SEMANTIC_COLORS],
include: [LIGHT_COLORS, LIGHT_SCHEME],
filter: (token: TransformedToken) =>
includeTokenFilter(token, ['Semantic']),
buildPath: SCHEME_BUILD_PATH,
fileName: 'light-semantic',
selector: '[data-color-scheme="light"]',
prefix: COLOR_PREFIX,
outputReferences: false,
})

const darkSemanticColors = _extend({
source: [SEMANTIC_COLORS],
include: [DARK_COLORS, DARK_SCHEME],
filter: (token: TransformedToken) =>
includeTokenFilter(token, ['Semantic']),
buildPath: SCHEME_BUILD_PATH,
fileName: 'dark-semantic',
selector: '[data-color-scheme="dark"]',
prefix: COLOR_PREFIX,
outputReferences: false,
})

await lightSemanticColors.buildAllPlatforms()
await darkSemanticColors.buildAllPlatforms()
}

async function combineColorsFromConfig(cfg: TokenConfig) {
Expand Down
130 changes: 115 additions & 15 deletions packages/eds-tokens/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# @equinor/eds-tokens

[Design tokens] used in the Equinor Design System (EDS), such as colours, spacings and typography.
[Design tokens] used in the <abbr title="Equinor Design System">EDS</abbr>, including colors, spacing, typography, and more. These tokens are synchronized with Figma variables and provide a single source of truth for design decisions across the design system.

## Installation

Expand All @@ -10,28 +10,128 @@ pnpm add @equinor/eds-tokens

## Usage

```js
import { tokens } from '@equinor/eds-tokens'
The package provides two token systems:

* **CSS Variables (Recommended)** -- Modern, theme-aware design tokens synced from Figma
* **Legacy Tokens** -- Original token format, still supported for backward compatibility

---

## CSS Variables (Recommended)

The new token system uses CSS custom properties that automatically adapt to light and dark color schemes using the modern `light-dark()` function. These tokens are directly synced from Figma variables.

### Using CSS Variables in CSS

Import the variables stylesheet:

```css
@import '@equinor/eds-tokens/css/variables';
```

Then use the CSS custom properties in your styles:

```css
.my-component {
background-color: var(--eds-color-bg-neutral-surface);
color: var(--eds-color-text-neutral-strong);
border: 1px solid var(--eds-color-border-neutral-subtle);
padding: var(--eds-spacing-inline-md);
border-radius: var(--eds-spacing-border-radius-rounded);
}
```

CSS custom properties are also available:
The variables automatically respond to color scheme changes:

```css
@import '@equinor/eds-tokens/css/variables-static.css'; /* or variables-dynamic.css */
/* Applies to elements with data-color-scheme attribute */
[data-color-scheme="dark"] {
/* Variables automatically use dark mode values */
}

/* Or use the native prefers-color-scheme */
@media (prefers-color-scheme: dark) {
/* Variables automatically use dark mode values */
}
```

### Using variables in JavaScript/TypeScript

For scenarios where you need colour variables in JavaScript:

#### Color Scheme Tokens

Import the light and dark semantic color tokens:

```typescript
// Import semantic color scheme tokens
import * as lightSemantic from '@equinor/eds-tokens/js/color/color-scheme/light-semantic'
import * as darkSemantic from '@equinor/eds-tokens/js/color/color-scheme/dark-semantic'

// Use semantic tokens with light/dark values
const lightSurface = lightSemantic.BG_NEUTRAL_SURFACE
const darkSurface = darkSemantic.BG_NEUTRAL_SURFACE

const lightAccent = lightSemantic.BG_ACCENT_FILL_EMPHASIS_DEFAULT
const darkAccent = darkSemantic.BG_ACCENT_FILL_EMPHASIS_DEFAULT

const lightBorder = lightSemantic.BORDER_INFO_MEDIUM
const darkBorder = darkSemantic.BORDER_INFO_MEDIUM
```

#### Spacing Tokens

```typescript
// Import spacing values for different density modes
import * as comfortableSpacing from '@equinor/eds-tokens/js/spacing/comfortable'
import * as spaciousSpacing from '@equinor/eds-tokens/js/spacing/spacious'

// Use the values (numbers in pixels)
const padding = comfortableSpacing.SPACING_INLINE_MD
const borderRadius = comfortableSpacing.SPACING_BORDER_RADIUS_ROUNDED
```

### Available Token Categories

* **Colors** -- Semantic color tokens for backgrounds, text, borders, and states
* **Spacing** -- Layout spacing including inline, stack, inset, and border radius
* **Typography** -- Font sizes, line heights, and font families (requires font files)

### Spacing Density Modes

The spacing system supports different density modes:

* `comfortable` -- Default density for most applications
* `spacious` -- Increased spacing for better readability

---

## Legacy Tokens (Backward Compatible)

The original token format is still available for existing applications. These tokens use a structured JavaScript object format.

### Using Legacy Tokens in JavaScript/TypeScript

```javascript
import { tokens } from '@equinor/eds-tokens'

// Access token values
const primaryColor = tokens.colors.interactive.primary__resting.rgba
const spacing = tokens.spacings.comfortable.medium
const typography = tokens.typography.heading.h1
```

`variables-static.css` exposes tokens with fixed values, while
`variables-dynamic.css` includes dynamic semantic color tokens.
### Legacy Token Categories

## Tokens
* Clickbounds
* Colors
* Elevation
* Shape
* Spacing
* Interaction states
* Typography (`ot`, `woff` or `woff2` font required)

- Clickbounds
- Colors
- Elevation
- Shape
- Spacing
- Interaction states
- Typography (`ot`, `woff` or `woff2` font required)
> We recommend migrating to CSS Variables for new projects to benefit from automatic theme support and better performance.

[design tokens]: https://css-tricks.com/what-are-design-tokens/

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* Do not edit directly, this file was auto-generated.
*/

[data-color-scheme="dark"] {
--eds-color-bg-neutral-canvas: #0b0b0b;
--eds-color-bg-neutral-surface: #202223;
--eds-color-bg-neutral-fill-muted-default: #525c65;
--eds-color-bg-neutral-fill-muted-hover: #5d6b76;
--eds-color-bg-neutral-fill-muted-active: #6b7d8b;
--eds-color-bg-neutral-fill-emphasis-default: #b4c7d7;
--eds-color-bg-neutral-fill-emphasis-hover: #cadae7;
--eds-color-bg-neutral-fill-emphasis-active: #deeaf4;
--eds-color-bg-accent-canvas: #0a0b0b;
--eds-color-bg-accent-surface: #1e2323;
--eds-color-bg-accent-fill-muted-default: #3c6266;
--eds-color-bg-accent-fill-muted-hover: #3e7378;
--eds-color-bg-accent-fill-muted-active: #41878e;
--eds-color-bg-accent-fill-emphasis-default: #8cd2da;
--eds-color-bg-accent-fill-emphasis-hover: #ace3e9;
--eds-color-bg-accent-fill-emphasis-active: #c7f1f6;
--eds-color-bg-success-canvas: #0a0c0a;
--eds-color-bg-success-surface: #1e231e;
--eds-color-bg-success-fill-muted-default: #3c673a;
--eds-color-bg-success-fill-muted-hover: #3e793c;
--eds-color-bg-success-fill-muted-active: #418e3e;
--eds-color-bg-success-fill-emphasis-default: #8cdb87;
--eds-color-bg-success-fill-emphasis-hover: #aceba8;
--eds-color-bg-success-fill-emphasis-active: #c7f7c3;
--eds-color-bg-info-canvas: #0a0b0c;
--eds-color-bg-info-surface: #1d2226;
--eds-color-bg-info-fill-muted-default: #33607e;
--eds-color-bg-info-fill-muted-hover: #316f98;
--eds-color-bg-info-fill-muted-active: #2e82b7;
--eds-color-bg-info-fill-emphasis-default: #7dceff;
--eds-color-bg-info-fill-emphasis-hover: #a2e0ff;
--eds-color-bg-info-fill-emphasis-active: #c4eeff;
--eds-color-bg-warning-canvas: #0c0b0a;
--eds-color-bg-warning-surface: #27201b;
--eds-color-bg-warning-fill-muted-default: #7e4e25;
--eds-color-bg-warning-fill-muted-hover: #97571b;
--eds-color-bg-warning-fill-muted-active: #b46201;
--eds-color-bg-warning-fill-emphasis-default: #ffad63;
--eds-color-bg-warning-fill-emphasis-hover: #ffc791;
--eds-color-bg-warning-fill-emphasis-active: #ffddb9;
--eds-color-bg-danger-canvas: #0d0a0a;
--eds-color-bg-danger-surface: #2a1e1e;
--eds-color-bg-danger-fill-muted-default: #923a3c;
--eds-color-bg-danger-fill-muted-hover: #b03940;
--eds-color-bg-danger-fill-muted-active: #d43745;
--eds-color-bg-danger-fill-emphasis-default: #ffa3a1;
--eds-color-bg-danger-fill-emphasis-hover: #ffc1bf;
--eds-color-bg-danger-fill-emphasis-active: #ffd9d7;
--eds-color-border-neutral-subtle: #525c65;
--eds-color-border-neutral-medium: #738696;
--eds-color-border-neutral-strong: #9fb4c6;
--eds-color-border-accent-subtle: #3c6266;
--eds-color-border-accent-medium: #439199;
--eds-color-border-accent-strong: #6ec0c9;
--eds-color-border-success-subtle: #3c673a;
--eds-color-border-success-medium: #449941;
--eds-color-border-success-strong: #6eca6a;
--eds-color-border-info-subtle: #33607e;
--eds-color-border-info-medium: #2d8bc5;
--eds-color-border-info-strong: #5abbfb;
--eds-color-border-warning-subtle: #7e4e25;
--eds-color-border-warning-medium: #c36800;
--eds-color-border-warning-strong: #f99539;
--eds-color-border-danger-subtle: #923a3c;
--eds-color-border-danger-medium: #e53748;
--eds-color-border-danger-strong: #ff8082;
--eds-color-text-neutral-subtle: #d6e3ee; /** Used for text and icons */
--eds-color-text-neutral-strong: #f5fdff; /** Used for text and icons */
--eds-color-text-neutral-subtle-on-emphasis: #333639; /** Text or icons against colored backgrounds */
--eds-color-text-neutral-strong-on-emphasis: #030303; /** Text or icons against colored backgrounds */
--eds-color-text-accent-subtle: #bcebf1; /** Used for text and icons */
--eds-color-text-accent-strong: #e6ffff; /** Used for text and icons */
--eds-color-text-accent-subtle-on-emphasis: #2c3839; /** Text or icons against colored backgrounds */
--eds-color-text-accent-strong-on-emphasis: #030303; /** Text or icons against colored backgrounds */
--eds-color-text-success-subtle: #bcf2b8; /** Used for text and icons */
--eds-color-text-success-strong: #e6ffe3; /** Used for text and icons */
--eds-color-text-success-subtle-on-emphasis: #2c392b; /** Text or icons against colored backgrounds */
--eds-color-text-success-strong-on-emphasis: #030303; /** Text or icons against colored backgrounds */
--eds-color-text-info-subtle: #b7e8ff; /** Used for text and icons */
--eds-color-text-info-strong: #ecffff; /** Used for text and icons */
--eds-color-text-info-subtle-on-emphasis: #2a3741; /** Text or icons against colored backgrounds */
--eds-color-text-info-strong-on-emphasis: #030304; /** Text or icons against colored backgrounds */
--eds-color-text-warning-subtle: #ffd4aa; /** Used for text and icons */
--eds-color-text-warning-strong: #fff7e6; /** Used for text and icons */
--eds-color-text-warning-subtle-on-emphasis: #413226; /** Text or icons against colored backgrounds */
--eds-color-text-warning-strong-on-emphasis: #040303; /** Text or icons against colored backgrounds */
--eds-color-text-danger-subtle: #ffd0ce; /** Used for text and icons */
--eds-color-text-danger-strong: #fff5f4; /** Used for text and icons */
--eds-color-text-danger-subtle-on-emphasis: #492d2c; /** Text or icons against colored backgrounds */
--eds-color-text-danger-strong-on-emphasis: #040303; /** Text or icons against colored backgrounds */
}
Loading
Loading