Palette Guard

Simulates colour-blind vision for chart series and flags pairs that become hard to tell apart, with the smallest lightness fix.

StopsChart colours look identical to colour-blind readers

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/palette-guard.json

The files land in your project. They're yours to edit.

Usage

palette-guard-usage.tsx
import { PaletteGuard, type Series } from "@/components/ui/palette-guard"

<PaletteGuard value={series} onValueChange={setSeries} />

What it catches

  • Series pairs that look alike for protan, deutan or tritan vision
  • Pairs already too close in normal vision
  • Smallest lightness-only fix that clears every clash
  • Cases needing patterns or direct labels instead

Props

PaletteGuard props
PropTypeDefault
value

Controlled palette, one entry per chart series.

Series[]—
defaultValue

Initial palette when uncontrolled.

Series[][]
onValueChange

Called with the new palette when a colour is edited or a fix is applied.

(value: Series[]) => void—
minDelta

Smallest CIEDE2000 difference that still reads as two series. 6 passes Okabe–Ito and fails red/green.

number6
visionLabels

Row names for each kind of vision.

Record<Vision, string>{ normal: "Typical vision", protan: "Red-blind (protan)",…
clashText

Templates: `{a}`, `{b}`, `{vision}`, `{delta}`, `{name}`, `{direction}`.

string"{a} and {b} look alike to {vision} readers (ΔE {delta})."
normalClashText

Shown when a pair is too close in normal vision.

string"{a} and {b} are hard to tell apart for everyone (ΔE {del…
fixText

Fix button template.

string"{direction} {name}"
noFixText

Shown when no lightness change can clear every clash.

string"No colour change separates them without breaking another…
passText

Shown when every pair is distinguishable.

string"All {count} series stay distinct for red-, green- and bl…

* required. Also accepts the native props of <div> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Series list is labelled; each colour input has an aria-label
  • Clash status is in a polite live region and marked in text (", clashes")
  • Fix button has an aria-label describing the change

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

  • Simulates full dichromacy (severity 1.0); milder forms are not modelled separately
  • A colour difference threshold isn't the same as legibility on your background
  • Doesn't check text contrast

What it stops

Chart colours look identical to colour-blind readers

Also known as

color palette · colour blind · chart colors · a11y · deuteranopia · okabe-ito · data viz · contrast

Dependencies

Pairs well with