Skip to main content

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.

Solid color tokens. Select a swatch to copy its token.
Palettes10s20s30s40s50s60s70s80s90s100s110s120
Neutral
Blue
Red
Orange
Yellow
Green
Purple
Pink
BackgroundsInteractiveBordersSolidText

What each step is for

StepsUse for
s00–s25App and component backgrounds
s30–s55Interactive backgrounds: default, hover, pressed
s60–s85Borders and separators, from subtle to strong
s90–s105Accent fills and their hover states
s110–s125Text, 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

TokenDefaultHoverActiveDisabled

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

TokenDefaultHoverActiveDisabled
———
———
—
—
—
———

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

TokenDefaultHoverActiveDisabled

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.

Update available
status.infoBlue
Changes saved
status.successGreen
Review before continuing
status.warningOrange
Unable to save
status.errorRed

Brand 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.

StepsJobSemantic tokens
s00–s25App and component backgroundsbg.min · bg.surface
s30–s55Interactive backgrounds: default, hover, pressedbg.subtle · bg.shaded
s60–s85Borders and separators, from subtle to strongbd.subtle · bd.solid · bd.strong
s90–s105Accent fills and their hover statesbg.solid (neutral uses s125)
s110–s125Text, from lower to higher contrastfg.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.min through bg.shaded and 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 .disabled value 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.

Palette
Layer 1
Layer 2
Layer 3
Nested bg.subtle
Layer 1
Layer 2
Layer 3
Nested bg.surface
bg.surface
bg.subtlebd.subtle
bg.shadedbd.solid
Progressive depth

Borders on backgrounds

Every border token is alpha, so the same border sits on any background level.

bd.strong
bd.solid
bd.subtle
On bg.min
bd.strong
bd.solid
bd.subtle
On bg.surface
bd.strong
bd.solid
bd.subtle
On bg.subtle
bd.strong
bd.solid
bd.subtle
On bg.shaded

Rules

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?

On this page

Privacy