Skip to content
Back to Design Hub

Gradient System & Tokens

Tokenized gradient stops and presets so gradients stay on-brand and consistent.

Visual DesignIntermediate

Why

Hand-picked hex pairs for every gradient drift off-brand, clash with the palette, and can't adapt to dark mode. A tokenized gradient system (stops + presets) keeps them consistent and themeable.

Google's research shows users form a first impression in 50ms, and 75% of judgments about website credibility are based on visual aesthetics. Consistent spacing scales (8px grid) reduce cognitive load measurably.

When

Any app using 3+ gradients (hero backgrounds, buttons, badges). One-off marketing gradients can stay inline; product gradients should be tokens.

How

1. Stops — define color stops as tokens: --grad-brand-1: var(--color-brand-500), --grad-brand-2: var(--color-brand-700) 2. Presets — compose stops into named gradients: --grad-brand: linear-gradient(135deg, var(--grad-brand-1), var(--grad-brand-2)) 3. Angle as token — --grad-angle-hero: 135deg; reuse across hero variants 4. Dark mode — redefine stops in [data-theme="dark"]; the preset inherits automatically 5. Radial/conic — separate presets for radial (spotlight) and conic (color wheel); don't force one type 6. Mesh gradients — multi-stop linear approximations; true mesh gradients are heavy (SVG/filter) 7. Text on gradient — always check contrast; gradient backgrounds need a solid fallback for high-contrast mode

Example

:root { /* Stops — reference the color tokens, not raw hex */ --grad-brand-1: var(--color-brand-500); --grad-brand-2: var(--color-brand-700); --grad-surface-1: var(--color-gray-50); --grad-surface-2: var(--color-gray-200); --grad-angle: 135deg; /* Presets — compose stops into named gradients */ --grad-brand: linear-gradient(var(--grad-angle), var(--grad-brand-1), var(--grad-brand-2)); --grad-surface: linear-gradient(180deg, var(--grad-surface-1), var(--grad-surface-2)); --grad-spotlight: radial-gradient(circle at 30% 20%, var(--color-brand-300), transparent 60%); } [data-theme="dark"] { --grad-surface-1: var(--color-gray-800); /* preset inherits */ --grad-surface-2: var(--color-gray-900); } /* Usage */ .hero { background: var(--grad-brand); } .card { background: var(--grad-surface); } .badge { background: var(--grad-spotlight); } /* High-contrast fallback */ @media (prefers-contrast: more) { .hero { background: var(--color-brand-600); } /* solid, no gradient */ }

Common Problems

  • ⚠Raw hex in every gradient — drifts off-brand, can't adapt to dark mode without re-declaring
  • ⚠No high-contrast fallback — gradient text becomes unreadable in forced-colors mode
  • ⚠Too many stops — 5-stop 'mesh' gradients are heavy to render and look muddy

Best Practices

  • ✓Tokenize stops (reference color tokens) + presets (compose stops) — themeable, consistent
  • ✓Provide a solid fallback for prefers-contrast: more — gradients can fail in forced-colors
  • ✓Keep 2–3 stops — more looks muddy; use a radial or SVG mesh for true multi-color effects

FAQ