Guide

Building Accessible Color Palettes

An accessible palette is one everyone can actually use: legible text, distinguishable states, and no meaning carried by color alone. Building that in is far cheaper than retrofitting it.

Two designers reviewing an accessible color palette with navy, cream and amber swatches and geometric shapes

An accessible palette is one everyone can actually use. That means legible text, distinguishable states, and no meaning carried by color alone. Building accessibility into the palette from the start is far cheaper than retrofitting it, and this guide covers the whole sequence.

Key takeaways

  • 4.5:1 for body text, 3:1 for large text and interface components, 7:1 for AAA.
  • Contrast depends on lightness far more than on hue.
  • Fix failing pairs by moving lightness, not by abandoning the color.
  • Color must never be the only channel carrying meaning.

Contrast is the foundation

The WCAG contrast ratio compares the perceived brightness of two colors, on a scale from 1:1 to 21:1. Three thresholds matter in practice:

  • 4.5:1 for normal body text (AA).
  • 3:1 for large text, meaningful graphics and interface components (AA Large).
  • 7:1 for the stricter AAA standard, worth targeting for long-form reading.

Contrast depends on lightness far more than hue, which is why two vivid colors of similar lightness can look bold together and still fail badly the moment one carries words.

Accessible color palette examples comparing passing and failing text contrast on colored backgrounds
A palette needs at least one pairing that passes 4.5:1 for body text.

Plan text pairings early

As soon as you generate a palette, decide which color carries text and which sits behind it. If your only dark and only light colors fail together, the palette has no legal text pairing and needs fixing before anything is built on top of it. Discovering this after a layout exists is how accessibility work becomes expensive.

Fix contrast with lightness, not hue

When a pairing fails, adjust lightness rather than changing the color's identity. Push the text darker or the background lighter. Because contrast tracks lightness, a change of a few percent often flips a fail into a pass while the color still reads as the same color. The converter shows the exact HSL lightness so you can move by number rather than by nudging a picker.

Build ramps so choices become lookups

Real interfaces need more than one dark and one light. Generate a five- to nine-step ramp from each brand color, then record which steps pass against your standard surfaces. Designers and developers then pick a step that is already known to pass, instead of re-deriving the answer for every component. This is the single change that makes accessibility scale across a team.

Never rely on color alone

Contrast handles legibility; it does not handle meaning. If red versus green is the only difference between success and error, users who cannot distinguish those hues receive no information at all. Pair color with an icon, a label or a shape. This is central to designing for color blindness, where the same rule is the whole discipline.

Convert your palette to greyscale. If two colors that must be told apart become the same grey, someone will confuse them.

Do not forget focus and state

Focus rings, hover states, disabled controls and placeholder text are where accessible palettes most often break, because they are designed last and tested least. A focus indicator needs 3:1 against both the component and its background; disabled text still has to be readable enough to explain why a control is unavailable. Give these states their own tokens rather than improvising them per component.

Test the real thing

Ratios are necessary but not sufficient. Preview real text at its real size on the real background — thin fonts, small sizes and translucent overlays all erode effective contrast in ways a number cannot capture. Run every pairing through the contrast checker, then confirm with your own eyes on a real screen.

Make the accessible choice the default one

Accessibility survives in a codebase for the same reason anything else survives: it is easier to do than to avoid. Ship the palette so that the correct pairing is the default value of a component, so that the token names say what they are for, and so that an incorrect combination requires an explicit override. Automated checks in continuous integration help, but they arrive late. The earlier lever is the design of the system itself, where a well-named token quietly prevents a whole class of failures before anyone writes a line of code that would need testing.

Frequently asked questions

Does WCAG apply to decorative color?

No. Purely decorative graphics and disabled controls are exempt, but anything that conveys information or receives interaction is in scope.

What contrast do placeholder and helper text need?

The same 4.5:1 as body text. Placeholder text is frequently the least readable element on a form, and it usually carries instructions.

Is AAA worth targeting?

For long-form reading and for audiences with a wide age range, yes. For most interfaces, AA with generous margins is the practical target.

For the same material in article form, see building accessible palettes from the start.

Build a palette now

Put this guide into practice with the free generator, converter and contrast checker.

Open the generator