- Accordion
- Avatar
- Badge
- Breadcrumb
- Button
- Calendar
- Checkbox
- Combobox
- Container
- CurrencyInput
- DistributionSlider
- Drawer
- Dropdown
- Grid
- Heading
- Image
- Input
- InputGroup
- Label
- Logo
- MapPin
- Modal
- NativeSelect
- NumberInput
- OtpInput
- PhoneInput
- Popover
- Progress
- PropertyCalendar
- RadioGroup
- RadioGroupCards
- ResponsiveModal
- ScrollArea
- SearchBar
- SearchBarFallback
- SearchInput
- Select
- Separator
- Spinner
- Switch
- Tabs
- Text
- Textarea
- Toast
- Toggle
- ToggleGroup
- Tooltip
Design tokens
Shared design values for web following the DSCG v1 spec.
Background surface
button
border
neutral
orange
red
yellow
green
blue
purple
pink
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
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.
| Class | Size | Line height | Letter spacing | Use |
|---|---|---|---|---|
text-display-lg | 52px | 56px | -0.02em | Hero headlines |
text-display | 36px | 40px | -0.02em | Page titles |
text-display-sm | 32px | 32px | -0.02em | Section titles |
text-headline-lg | 30px | 36px | -0.01em | Large headings |
text-headline | 24px | 28px | -0.01em | Standard headings |
text-headline-sm | 16px | 20px | 0 | Small headings |
text-body-lg-long | 16px | 24px | 0 | Large body, multi-line |
text-body-lg | 16px | 20px | 0 | Large body, single-line |
text-body-long | 14px | 20px | 0 | Body text, multi-line |
text-body | 14px | 17px | 0 | Default body text |
text-body-sm | 12px | 15px | 0 | Captions, 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>Two weights are defined as custom values to align with Instrument Sans optical weight:
| Class | Value |
|---|---|
font-normal | 450 |
font-medium | 550 |
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>18 easing curves across three families. Use with the ease-* utility class for transitions and animations.
| Family | Curves |
|---|---|
| Ease in | ease-in-quad, ease-in-cubic, ease-in-quart, ease-in-quint, ease-in-expo, ease-in-circ |
| Ease out | ease-out-quad, ease-out-cubic, ease-out-quart, ease-out-quint, ease-out-expo, ease-out-circ |
| Ease in-out | ease-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>Responsive breakpoints for use with Tailwind responsive prefixes (sm:, md:, etc.).
| Prefix | Width | Pixels |
|---|---|---|
sm | 40rem | 640px |
md | 46.5rem | 744px |
lg | 65rem | 1040px |
xl | 80.5rem | 1288px |
2xl | 90rem | 1440px |
3xl | 104.75rem | 1676px |
4xl | 120.5rem | 1928px |
The md breakpoint (744px) is the primary mobile/desktop threshold used by useIsDesktop and useIsMobile in the shared utils.
Beyond standard Tailwind, the token stylesheet provides compound utilities that wire up interactive states automatically.
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.
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>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>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>pnpm add @wandercom/design-system-tokensSee the installation guide for authentication setup.
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>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-tokensimport {
generateScales,
resolveRoleTokens,
generateExportCSS,
type SeedColors,
} from '@wandercom/design-system-tokens/color-engine';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
};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 stopFor a single color, use generateScale:
import { generateScale } from '@wandercom/design-system-tokens/color-engine';
const brandScale = generateScale('#1a1a2e');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.
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 modeBackgroundRole is a union of all supported contexts:
| Group | Roles |
|---|---|
| Neutral | white, black |
| Theme | theme-light, theme-base, theme-dark |
| Accent Primary | accent-primary-light, accent-primary-base |
| Accent Secondary | accent-secondary-light, accent-secondary-base, accent-secondary-dark |
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 heroLow-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 alphaGenerate 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).
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';- Installation guide - Set up tokens in your project
- Web components - React components using tokens