Skip to main content
Audit & Compliance

Contrast as a release gate for a token package

DesignerDeveloperQA

Overview

Code scans find code bugs. Contrast checks find design bugs. Check every token pair that meets in the UI in light and dark before a token release ships, and let the gate block.

A design system's own tokens can fail contrast before any developer touches them. In one two-app setup, every input border in the Figma library sat below 3:1 against white, and the subtle border was 1.4:1. Muted text inside recessed panels fell just under 4.5:1. No code scan would have flagged either, because the code used the tokens exactly as designed. The fix is to treat contrast as a gate on the token release itself: list the pairs that will actually meet in the UI (text on each surface, status text on its status surface, control borders on white), check each in light and dark mode, and fail the release when a pair drops below 4.5:1 for text or 3:1 for control boundaries. Known gaps go on an allow list so they warn instead of block, and the release notes carry the contrast report next to the token diff. Dembrandt supplies the rendered side: run it with --wcag against the deployed app in light and dark mode and the report shows the pairs the browser actually produced, which is how the border problem surfaced in the first place. The outcome in that case was a new control-border token in the design system, not a code change.

Rendered contrast, light mode

Terminal
dembrandt https://app.example.com --wcag --save-output

Rendered contrast, dark mode

Terminal
dembrandt https://app.example.com --wcag --dark-mode --save-output
Claude Code prompt
# Load both extractions and the token package's tokens.json, then:
"List every token pair that meets in the UI: text on each surface,
status ink on its status surface, control borders on the page background.
For each pair, in light and dark:
PAIR | LIGHT RATIO | DARK RATIO | REQUIRED | VERDICT
Required is 4.5:1 for text, 3:1 for control boundaries.
Mark pairs below the requirement as FAIL unless they are on the
known-gaps list, which downgrades them to WARN.
End with the tokens that need a new value, and whether the fix
belongs in the design system or in one app."
Output

A contrast table per token pair in both modes, a pass/fail verdict the release pipeline can block on, and the list of tokens the design system itself needs to change.

Browse all

All recipes →

64 workflows