Open DS

Color

Five questions every design system answers about color. These are Accessible first’s answers, and each one points back to the reasons that chose it.

View all 41 color tokens ↓

The reasons this scheme answers from

  • R1Human factorsLow effort to understand, they see it fresh each time
  • R2People and work contextEveryone, including people with disabilities, AAA
  • R3BrandCalm and clear, quiet
  • R4OutcomesCompletion without errors, a task that fails

Question 1

Which color roles does it need?

  • Surface, text, action and status (chosen)
  • Those and brand accents

Why Accessible first picks it: Few color roles, each with one clear meaning.

becauseR1

surface
text
border
action
status
category
disabled

Question 2

How many emphasis levels do actions need?

  • Two (chosen)
  • Three
  • Four

Why Accessible first picks it: Primary and secondary only; fewer choices, fewer errors.

becauseR1

gray light7
blue light3
black light1
teal light3
green light2
amber light2
red light2

Question 3

How is the palette defined?

  • Neutrals and one brand ramp (chosen)
  • Shared neutrals, a ramp per brand

Why Accessible first picks it: True neutrals and one strong blue, checked for contrast.

becauseR2

  • Neutrals and one brand ramp
  • from color.gray.light
  • from color.blue.light
  • from color.black.light
  • from color.teal.light
  • from color.green.light
  • from color.amber.light
  • from color.red.light

Decisions point at primitives, so the rule lives in one place.

Question 4

How saturated is the palette?

  • Muted
  • Balanced (chosen)
  • Vivid

Why Accessible first picks it: Strong but not loud color.

becauseR3

  • surface
    canvas
    → color.gray.light.50· dark → color.gray.dark.0
    default
    → color.gray.light.0· dark → color.gray.dark.50
    raised
    → color.gray.light.0· dark → color.gray.dark.100
    sunken
    → color.gray.light.100· dark → color.gray.dark.100
    selected
    → color.blue.light.100· dark → color.blue.dark.100
    inverse
    → color.gray.light.900· dark → color.gray.dark.900
    scrim
    → color.black.light.scrim· dark → color.black.dark.scrim
  • text
    primary
    → color.gray.light.900· dark → color.gray.dark.900
    secondary
    → color.gray.light.700· dark → color.gray.dark.600
    muted
    → color.gray.light.500· dark → color.gray.dark.500
    inverse
    → color.gray.light.0· dark → color.gray.dark.50
    on-action
    → color.gray.light.0· dark → color.gray.dark.0
    link
    → color.blue.light.700· dark → color.blue.dark.700
  • border
    default
    → color.gray.light.200· dark → color.gray.dark.100
    strong
    → color.gray.light.500· dark → color.gray.dark.400
    focus
    → color.blue.light.600· dark → color.blue.dark.700
  • action
    primary.@
    → color.blue.light.600· dark → color.blue.dark.700
    primary.hover
    → color.blue.light.700· dark → color.blue.dark.800
    secondary.@
    → color.gray.light.0· dark → color.gray.dark.50
    secondary.hover
    → color.gray.light.100· dark → color.gray.dark.100
  • status
    info.@
    → color.teal.light.700· dark → color.teal.dark.700
    info.subtle
    → color.teal.light.100· dark → color.teal.dark.100
    success.@
    → color.green.light.700· dark → color.green.dark.700
    success.subtle
    → color.green.light.100· dark → color.green.dark.100
    warning.@
    → color.amber.light.700· dark → color.amber.dark.700
    warning.subtle
    → color.amber.light.100· dark → color.amber.dark.100
    danger.@
    → color.red.light.700· dark → color.red.dark.700
    danger.subtle
    → color.red.light.100· dark → color.red.dark.100
  • category
    1.@
    → color.blue.light.600· dark → color.blue.dark.700
    1.subtle
    → color.blue.light.100· dark → color.blue.dark.100
    2.@
    → color.teal.light.600· dark → color.teal.dark.700
    2.subtle
    → color.teal.light.100· dark → color.teal.dark.100
    3.@
    → color.green.light.700· dark → color.green.dark.700
    3.subtle
    → color.green.light.100· dark → color.green.dark.100
    4.@
    → color.amber.light.700· dark → color.amber.dark.700
    4.subtle
    → color.amber.light.100· dark → color.amber.dark.100
    5.@
    → color.gray.light.500· dark → color.gray.dark.700
    5.subtle
    → color.gray.light.100· dark → color.gray.dark.100
  • disabled
    text
    → color.gray.light.500· dark → color.gray.dark.500
    surface
    → color.gray.light.100· dark → color.gray.dark.100
    border
    → color.gray.light.200· dark → color.gray.dark.200

Question 5

Where does color carry meaning first?

  • Status in tables
  • Links and actions (chosen)
  • Brand moments

Why Accessible first picks it: Links and actions must be found by everyone.

becauseR4

  • button · 13 keys
  • input · 8 keys
  • control · 3 keys
  • badge · 10 keys
  • card · 2 keys
  • table · 3 keys
  • tabs · 3 keys
  • overlay · 4 keys

When to use

  • A selected row or itemUse: color.surface.selected and a check icon. Not: Color alone. Selection never relies on color alone.
  • An error messageUse: color.status.danger, an icon and a sentence next to the field. Not: Color alone. People must know what went wrong and where.
  • A linkUse: color.text.link, underlined. Not: Color only. Underline works without color perception.
  • A statusUse: Badge with an icon and a word. Not: Color alone. Status must survive no color and a screen reader.
  • The action that completes the taskUse: Button primary, one per page. Not: Two primaries. One clear next step.
  • An alternative or cancelUse: Button secondary. Not: A text link. Every action looks like a button people can find.
  • Delete or removeUse: Button secondary, then a confirm page. Not: Button primary. A confirm step prevents a costly error.

All color tokens

41 tokens · each decision and the primitive it points to

  • color.gray.light · 7color.gray.light.50#F7F7F7color.gray.light.0#FFFFFFcolor.gray.light.100#EDEDEDcolor.gray.light.900#141414color.gray.light.700#333333color.gray.light.500#595959color.gray.light.200#D6D6D6
  • color.blue.light · 3color.blue.light.100#E1ECFFcolor.blue.light.700#083C93color.blue.light.600#0B4FC0
  • color.black.light · 1color.black.light.scrim#0000008C
  • color.teal.light · 3color.teal.light.700#0B5B55color.teal.light.100#E0F2F1color.teal.light.600#0F766E
  • color.green.light · 2color.green.light.700#1F7A3Acolor.green.light.100#E3F4EA
  • color.amber.light · 2color.amber.light.700#8A5600color.amber.light.100#FFF3D6
  • color.red.light · 2color.red.light.700#C42B2Bcolor.red.light.100#FDE7E7
  • Decisions · 41color.surface.canvas{color.gray.light.50}color.surface.default{color.gray.light.0}color.surface.raised{color.gray.light.0}color.surface.sunken{color.gray.light.100}color.surface.selected{color.blue.light.100}color.surface.inverse{color.gray.light.900}color.surface.scrim{color.black.light.scrim}color.text.primary{color.gray.light.900}color.text.secondary{color.gray.light.700}color.text.muted{color.gray.light.500}color.text.inverse{color.gray.light.0}color.text.on-action{color.gray.light.0}color.text.link{color.blue.light.700}color.border.default{color.gray.light.200}color.border.strong{color.gray.light.500}color.border.focus{color.blue.light.600}color.action.primary.@{color.blue.light.600}color.action.primary.hover{color.blue.light.700}color.action.secondary.@{color.gray.light.0}color.action.secondary.hover{color.gray.light.100}color.status.info.@{color.teal.light.700}color.status.info.subtle{color.teal.light.100}color.status.success.@{color.green.light.700}color.status.success.subtle{color.green.light.100}color.status.warning.@{color.amber.light.700}color.status.warning.subtle{color.amber.light.100}color.status.danger.@{color.red.light.700}color.status.danger.subtle{color.red.light.100}color.category.1.@{color.blue.light.600}color.category.1.subtle{color.blue.light.100}color.category.2.@{color.teal.light.600}color.category.2.subtle{color.teal.light.100}color.category.3.@{color.green.light.700}color.category.3.subtle{color.green.light.100}color.category.4.@{color.amber.light.700}color.category.4.subtle{color.amber.light.100}color.category.5.@{color.gray.light.500}color.category.5.subtle{color.gray.light.100}color.disabled.text{color.gray.light.500}color.disabled.surface{color.gray.light.100}color.disabled.border{color.gray.light.200}

Decisions reference primitives, so changing one primitive updates every decision and component that uses it.

Color in Accessible first: balanced. Strong but not loud color. Links and actions must be found by everyone.