Colors
Eight shared palettes, from backgrounds to text. Explore each step, then choose a semantic token for its job.
Palettes
Each palette has 26 solid steps (s00–s125) and a matching alpha scale (a00–a125). Start with the main steps, or reveal the full scale. Select a swatch to copy its token; hover or focus to see its value. Values follow the site's light or dark theme.
| Palette | s10 | s20 | s30 | s40 | s50 | s60 | s70 | s80 | s90 | s100 | s110 | s120 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Neutral | ||||||||||||
| Blue | ||||||||||||
| Red | ||||||||||||
| Orange | ||||||||||||
| Yellow | ||||||||||||
| Green | ||||||||||||
| Purple | ||||||||||||
| Pink | ||||||||||||
| Backgrounds | Interactive | Borders | Solid | Text | ||||||||
What each step is for
| Steps | Use for |
|---|---|
s00–s25 | App and component backgrounds |
s30–s55 | Interactive backgrounds: default, hover, pressed |
s60–s85 | Borders and separators, from subtle to strong |
s90–s105 | Accent fills and their hover states |
s110–s125 | Text, from lower to higher contrast |
The twelve main steps come from Radix Colors. Intermediate steps (s05, s15, and so on) use OKLCH interpolation. The endpoints extend the scale to its lightest and darkest values. A step's purpose is a starting point; check contrast in the final composition.
Semantic colors
Use these roles in components instead of choosing a raw step. The tables show the neutral palette, including each published interaction state. Select a token or value to copy its token name. A dash means there is no separate token for that state.
Panda color properties accept these names without the colors. prefix. Every palette provides the same roles: use blue.fg.body for a fixed palette, or colorPalette.fg.body within a reusable element.
Backgrounds
| Token | Default | Hover | Active | Disabled |
|---|---|---|---|---|
bg.min through bg.shaded are alpha colors: they blend with whatever is underneath. Their bgSolid.* equivalents are opaque. Use an opaque surface for popovers and dialogs. bg.solid is the opaque accent fill in either family.
Text
| Token | Default | Hover | Active | Disabled |
|---|---|---|---|---|
| — | — | — | ||
| — | — | — | ||
| — | ||||
| — | ||||
| — | ||||
| — | — | — |
Use fg.heading for titles and fg.body for reading and labels. Reserve fg.muted and fg.subtle for secondary information after checking contrast. Pair fg.onSolid with the same palette's bg.solid; the table shows this pair together.
Borders
| Token | Default | Hover | Active | Disabled |
|---|---|---|---|---|
Borders use alpha colors too. Pick enough contrast for the boundary's purpose; a decorative separator and an input outline do different jobs. Check focus indicators independently of these border roles.
Status and brand
Status colors keep the same meaning across brands. Pair the color with an icon and useful text, as in these examples.
status.infoBluestatus.successGreenstatus.warningOrangestatus.errorRedBrand colors identify a product; they do not redefine success, warning, or error. Each status alias has a complete set of roles, such as status.error.fg.body and status.error.bg.subtle.
How a scale is built
The main steps follow a shared progression: surface, interaction, border, accent, then text. Semantic tokens name the role and can choose different steps for particular palettes. For example, neutral bg.solid uses s125, while chromatic palettes use s90.
| Steps | Job | Semantic tokens |
|---|---|---|
s00–s25 | App and component backgrounds | bg.min · bg.surface |
s30–s55 | Interactive backgrounds: default, hover, pressed | bg.subtle · bg.shaded |
s60–s85 | Borders and separators, from subtle to strong | bd.subtle · bd.solid · bd.strong |
s90–s105 | Accent fills and their hover states | bg.solid (neutral uses s125) |
s110–s125 | Text, from lower to higher contrast | fg.body · fg.heading · fg.max |
import { css } from "@hashintel/ds-helpers/css";
export const accent = css({
colorPalette: "blue",
backgroundColor: "colorPalette.bg.solid",
color: "colorPalette.fg.onSolid",
_hover: { backgroundColor: "colorPalette.bg.solid.hover" },
});Opacity
Alpha steps reproduce the corresponding solid colors over the theme's reference ground. On another background, the result changes with the layers beneath it.
- Layered surfaces use alpha.
bg.minthroughbg.shadedand every border role blend with the surface below. - Solid fills and text stay opaque. Use
bgSolid.*when a panel must cover content beneath it. Foreground roles use solid values. - Keep content at full strength. Change a background token instead of applying opacity to a whole component, which also fades text, icons, and focus indicators.
- Disabled is a state token. Use the relevant
.disabledvalue and preserve the component's accessible behavior.
Color layering
Nest the same alpha level to add depth. Change the palette to see how the same roles behave across the color system. These examples use the live semantic tokens.
bg.subtlebg.surfaceBorders on backgrounds
Every border token is alpha, so the same border sits on any background level.
bd.strongbd.solidbd.subtlebg.minbd.strongbd.solidbd.subtlebg.surfacebd.strongbd.solidbd.subtlebg.subtlebd.strongbd.solidbd.subtlebg.shadedRules
Keep content legibleChange the background token, rather than reducing opacity on a whole component. Text and icons stay at full strength.
Use opaque floating surfacesUse bgSolid.surface or bgSolid.subtle for popovers and dialogs, so content beneath cannot show through.
Pair fills and foregroundsUse bg.solid with the same palette’s fg.onSolid. Yellow and orange can need dark text in the light theme.
Check text, control boundaries, and focus indicators in both themes. A name such as muted or subtle is not a guarantee of sufficient contrast. See Accessibility for targets, and DASH for setup and the token playground.
Last updated on 2026-10-31
Was this page helpful?