Color
The full spectrum palette and how to reference it.
Colour ships as CSS custom properties from @base-org/bds-tokens. Components
read those properties, so a palette change propagates everywhere without
touching component code.
@import '@base-org/bds-tokens/tokens/spectrum.css';Spectrum
Eleven hues, each running from 0 (lightest) to 100 (darkest) across
thirteen steps, plus a standalone brand colour. 50–60 is the usable
mid-range for interactive fills. Every swatch below is a token — its name is
--bds-{hue}-{step} and the class is bg-bds-{hue}-{step} — and the value
shown is the light-mode reference.
Blue
Teal
Green
Chartreuse
Yellow
Orange
Red
Pink
Purple
Indigo
Gray
Brand
Usage
Do
Reference tokens by name — bg-bds-blue-60, var(--bds-gray-20) — so the
value follows the palette and responds to dark mode.
Don't
Hard-code a hex value, even one copied from this page. It will not follow the ramp when the palette is retuned, and it will not switch for dark mode.
Steps
The thirteen steps are 0, 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100.
The gap is intentional: the scale is finer at the light end, where small
lightness changes read as distinct surfaces, and coarser at the dark end.
Semantic tokens
Semantic tokens name a role and resolve to one spectrum step per theme. Use
them for the surfaces, text, and hairlines that make up a page; reach for a
spectrum step directly only when a role does not fit, such as a status colour.
The name is --bds-{token} and the class is bg-bds-{token},
text-bds-{token}, or border-bds-{token}.
| Token | Role | Light | Dark |
|---|---|---|---|
bg-primary | Page and card background | gray-0 #ffffff | gray-0 #111111 |
bg-secondary | Raised or grouped surfaces: secondary buttons, input fills | gray-10 #efefef | gray-10 #3a3a3a |
bg-inverse | Inverted fills | gray-100 #111111 | gray-100 #ffffff |
fg-primary | Body text and icons | gray-80 #3a3a3a | gray-80 #efefef |
fg-muted | Secondary text and placeholders | gray-50 #6f6f6f | gray-50 #b8b8b8 |
fg-inverse | Text on an inverted fill | gray-0 #ffffff | gray-0 #111111 |
fg-on-brand | Text and icons on a brand fill | gray-0 #ffffff | gray-100 #ffffff |
border-default | Hairlines and rings | gray-10 #efefef | gray-10 #3a3a3a |
brand | Base Blue, for the wordmark and brand accents | blue-60 #0052ff | blue-40 #266eff |
The grays mirror between themes, so most tokens alias the same step in both;
brand and fg-on-brand are the exceptions. Base Blue stays saturated in dark
mode, so text on it stays white: pair bg-bds-brand with text-bds-fg-on-brand
rather than text-bds-fg-inverse, which turns near-black in dark mode. In JS, getSemanticColor('brand', 'dark') from
@base-org/bds-tokens returns the hex value.
Dark mode
The spectrum stylesheet redefines every custom property under .dark, so the
same token name resolves correctly in both themes. Components never branch on
theme themselves — bg-bds-gray-5 is a light surface in light mode and a dark
surface in dark mode, from one class.
Guidelines
Defaults for using tokens and colour in BDS components and product UI. See the Guidelines overview for how to apply them.
Design tokens
- Have components consume tokens (colour, spacing, radius, shadow, motion, type scale) — never hardcoded values.
- Reference semantic tokens (
--color-text-secondary), never primitives (--blue-500) — the primitive is the raw value, the token is how it's used. - Name tokens by purpose, not by raw value or one screen's use case
(
--color-accent-solid/--radius-card, not--blue-button/--8px). - Follow a tiered system: primitive → semantic → component-level override only when a component truly needs a one-off.
- Add a token only once a component needs it; remove unused tokens. This applies to colour steps, the spacing scale, radii, shadows, and motion durations and easings alike.
- Keep Figma variables and code tokens in sync — one source of truth, no drift.
Colour
- Reserve
accentfor the brand colour; don't letprimarymean both brand and body text. - Measure contrast against the background directly behind the element.
fg-mutedpasses 4.5:1 onbg-primaryandgray-5but not onbg-secondaryin light mode (4.37:1); usegray-60for muted text there. - Use a separate palette for dark mode, not an inversion of the light-mode palette.
- Choose one theme-switching mechanism (
prefers-color-schemeor a.darkclass), never both. - Be intentional about gradient colour blending:
in oklab(even brightness),in oklch(vivid midtones), orin srgb(muted midtones).