Design tokens

Shared design values for web following the DSCG v1 spec.

Colors

Background surface

button

border

neutral

orange

red

yellow

green

blue

purple

pink

Shadows

Shadow tokens provide consistent elevation across components. Each shadow is tuned for a specific UI context. Click any swatch to copy its Tailwind class.

Focus rings

Typography

The type system uses Instrument Sans with custom OpenType feature settings. All sizes bundle font-size, line-height, and letter-spacing into a single Tailwind class.

Type scale

ClassSizeLine heightLetter spacingUse
text-display-lg52px56px-0.02emHero headlines
text-display36px40px-0.02emPage titles
text-display-sm32px32px-0.02emSection titles
text-headline-lg30px36px-0.01emLarge headings
text-headline24px28px-0.01emStandard headings
text-headline-sm16px20px0Small headings
text-body-lg-long16px24px0Large body, multi-line
text-body-lg16px20px0Large body, single-line
text-body-long14px20px0Body text, multi-line
text-body14px17px0Default body text
text-body-sm12px15px0Captions, fine print
<h1 className="text-display font-medium">Page title</h1>
<p className="text-body-long text-secondary">Description text with comfortable reading line height.</p>
<span className="text-body-sm text-tertiary">Caption</span>

Font weights

Two weights are defined as custom values to align with Instrument Sans optical weight:

ClassValue
font-normal450
font-medium550

OpenType features

The default font-feature-settings are applied globally: 'ss01' (rounded dots), 'ss03' (alternate y), 'ss12' (alternate currency), 'ss09' (alternate Q), 'kern'.

Link tokens and utilities handle external and internal link styling with built-in hover states.

Styles an element as an external link using color-link (blue-500). On hover, the color shifts to color-link-hover and an underline appears.

<a href="https://wander.com" className="text-link">
  Visit Wander
</a>

Styles an element as an internal link using the primary text color. On hover, an underline appears. Use this for in-app navigation where blue link styling is not appropriate.

<a href="/docs/components/button" className="text-link-internal">
  Button component
</a>

Easing

18 easing curves across three families. Use with the ease-* utility class for transitions and animations.

FamilyCurves
Ease inease-in-quad, ease-in-cubic, ease-in-quart, ease-in-quint, ease-in-expo, ease-in-circ
Ease outease-out-quad, ease-out-cubic, ease-out-quart, ease-out-quint, ease-out-expo, ease-out-circ
Ease in-outease-in-out-quad, ease-in-out-cubic, ease-in-out-quart, ease-in-out-quint, ease-in-out-expo, ease-in-out-circ
<div className="transition-transform duration-300 ease-out-cubic hover:scale-105">
  Smooth scale on hover
</div>

<div className="transition-opacity duration-500 ease-in-out-quart">
  Fade with quartic easing
</div>

Breakpoints

Responsive breakpoints for use with Tailwind responsive prefixes (sm:, md:, etc.).

PrefixWidthPixels
sm40rem640px
md46.5rem744px
lg65rem1040px
xl80.5rem1288px
2xl90rem1440px
3xl104.75rem1676px
4xl120.5rem1928px

The md breakpoint (744px) is the primary mobile/desktop threshold used by useIsDesktop and useIsMobile in the shared utils.

Custom utilities

Beyond standard Tailwind, the token stylesheet provides compound utilities that wire up interactive states automatically.

bg-button-*

Applies background, text color, hover, and focus-visible states for a button variant in one class.

<button className="bg-button-primary rounded-lg px-4 py-2">Primary</button>
<button className="bg-button-checkout rounded-lg px-4 py-2">Book now</button>

Available variants: primary, secondary, outline, ghost, destructive, checkout, disabled, slider-thumb.

shadow-focus / shadow-focus-destructive

Focus ring tokens using a double box-shadow (inner surface ring + outer accent ring).

<button className="focus-visible:shadow-focus rounded-lg">Focusable</button>
<button className="focus-visible:shadow-focus-destructive rounded-lg">Destructive focus</button>

touch-hitbox

Expands the tap target to a minimum 44x44px hit area using a pseudo-element overlay, without changing visual size.

<button className="touch-hitbox">
  <SmallIcon />
</button>

scrollbar / scrollbar-thin / scrollbar-none

Control scrollbar appearance using native CSS scrollbar properties.

<div className="scrollbar-thin overflow-y-auto">Thin scrollbar</div>
<div className="scrollbar-none overflow-y-auto">Hidden scrollbar</div>

Installation

pnpm add @wandercom/design-system-tokens

See the installation guide for authentication setup.

Usage

Web

Import tokens in your application:

import '@wandercom/design-system-tokens/tailwind.css';

Tokens are available as Tailwind classes:

<h1 className="text-display font-medium">Welcome to Wander</h1>

<div className="bg-surface-primary text-primary">
  Content with design tokens
</div>

<a href="/properties" className="text-link-internal">
  Browse properties
</a>

<button className="bg-button-checkout focus-visible:shadow-focus rounded-lg px-4 py-2">
  Book now
</button>

<div className="shadow-dropdown rounded-xl border-overlay-primary bg-surface-dropdown p-2">
  Dropdown menu content
</div>

<div className="transition-transform duration-300 ease-out-cubic hover:scale-105">
  Animated element
</div>

Color engine

A self-contained color system built on OKLCh perceptual color space with WCAG contrast compliance. Given three seed colors, the engine generates full scales, resolves ~55 semantic tokens per background context, and exports to CSS or JSON.

pnpm add @wandercom/design-system-tokens
import {
  generateScales,
  resolveRoleTokens,
  generateExportCSS,
  type SeedColors,
} from '@wandercom/design-system-tokens/color-engine';

Seed colors

The entire palette derives from three hex seed colors:

import type { SeedColors } from '@wandercom/design-system-tokens/color-engine';

const seeds: SeedColors = {
  brand: '#1a1a2e',           // dominant brand hue (placed at scale stop 500)
  accentPrimary: '#e94560',   // action/CTA color
  accentSecondary: '#0f3460', // supporting variety color
};

Generating scales

generateScales produces a 9-stop scale (50, 100, 200, 300, 500, 700, 800, 900, 950) for each seed, preserving hue and scaling chroma proportionally.

import { generateScales } from '@wandercom/design-system-tokens/color-engine';

const scales = generateScales(seeds);

scales.brand[500];          // seed color
scales.accentPrimary[50];   // lightest accent stop

For a single color, use generateScale:

import { generateScale } from '@wandercom/design-system-tokens/color-engine';

const brandScale = generateScale('#1a1a2e');

Presets

11 named palettes are available as starting points:

import { PRESETS } from '@wandercom/design-system-tokens/color-engine';

const seeds = PRESETS['Ocean Calm'];
const scales = generateScales(seeds);

Available presets: Classic Persian, Pink Navy, Mauve Garden, Wander, Electric Clash, Ocean Calm, Sunset Warmth, Forest Dew, Coral Reef, Signal Pop, Heritage.

Resolving semantic tokens

Given a background context, the engine resolves a full set of semantic tokens (surfaces, text, buttons, borders, semantic colors) with WCAG-compliant contrast ratios.

import { resolveRoleTokens, type BackgroundRole } from '@wandercom/design-system-tokens/color-engine';

const { background, foreground, tokens } = resolveRoleTokens('theme-base', scales);

tokens.text.primary;           // WCAG AA against background
tokens.surface.secondary;      // slightly offset surface
tokens.button.background;      // CTA button fill
tokens.border.primary;         // default border
tokens.semantic.error;         // error color for the mode

BackgroundRole is a union of all supported contexts:

GroupRoles
Neutralwhite, black
Themetheme-light, theme-base, theme-dark
Accent Primaryaccent-primary-light, accent-primary-base
Accent Secondaryaccent-secondary-light, accent-secondary-base, accent-secondary-dark

Section and nav tokens

For page layout sections (optionally with background images) and navigation bars:

import {
  resolveSectionTokens,
  resolveNavTokens,
  type SectionConfig,
} from '@wandercom/design-system-tokens/color-engine';

const hero: SectionConfig = { role: 'theme-dark', img: true };

const section = resolveSectionTokens(hero, scales);
section.background;            // hex background
section.effectiveBackground;   // after image overlay blending
section.tokens.text.primary;   // collapsed to single level when img is present

const nav = resolveNavTokens(hero, scales);
nav.background;                // "transparent" for hero overlap
nav.backgroundBlur;            // frosted-glass tint
nav.ctaBackground;             // CTA button fill
nav.isTransparent;             // true when nav overlays hero

Color space utilities

Low-level color functions for conversion, contrast checking, and manipulation:

import {
  hexToOklch,
  oklchToHex,
  contrastRatio,
  ensureContrast,
  mixColors,
  alphaBlend,
  getLuminance,
  WCAG_AA,
} from '@wandercom/design-system-tokens/color-engine';

hexToOklch('#e94560');                          // { L, C, h } in OKLCh
oklchToHex(0.7, 0.15, 25);                     // hex with gamut clamping
contrastRatio('#ffffff', '#1a1a2e');             // WCAG 2.x ratio [1, 21]
ensureContrast('#888888', '#ffffff', WCAG_AA);  // adjusted hex meeting 4.5:1
mixColors('#ff0000', '#0000ff', 50);            // linear sRGB interpolation
alphaBlend('#000000', '#ffffff', 0.5);          // composite at alpha

Exporting tokens

Generate CSS custom properties or structured JSON for external consumers:

import { generateExportCSS, generateExportJSON } from '@wandercom/design-system-tokens/color-engine';

// CSS with [data-theme="..."] attribute selectors per background role
const css = generateExportCSS(scales);

// Structured JSON with seeds, primitives (scale stops), and modes (semantic tokens)
const json = generateExportJSON(seeds, scales);

The CSS output uses data-theme attribute selectors, mapping semantic tokens to CSS custom properties (e.g., --color-primary, --color-surface-secondary).

Constants

WCAG contrast thresholds are exported for use in custom validation:

import {
  WCAG_AA,              // 4.5 — normal-size text
  WCAG_AA_LARGE,        // 3   — large text / UI elements
  WCAG_AAA,             // 7   — enhanced contrast
  WCAG_TEXT_SECONDARY,  // 5.5 — secondary text
  WCAG_TEXT_MUTED,      // 3.5 — muted/placeholder text
} from '@wandercom/design-system-tokens/color-engine';