Checking color contrast is a core step in any accessibility review. The good news: it takes about 30 seconds per color pair when you have the right tool. The less good news: most teams skip it, and color contrast failures are consistently among the top WCAG violations found in audits.
This guide covers how to check contrast efficiently — during design, during development, and before you ship.
Why Color Contrast Matters
Around 8% of men and 0.5% of women have some form of color vision deficiency. More broadly, low-contrast text is hard to read for anyone in a bright environment, on a low-quality display, or with aging eyes. WCAG 2.1 requires:
- 4.5:1 for normal text (AA)
- 3:1 for large text — 18px+ regular weight, 14px+ bold — (AA)
- 7:1 for normal text (AAA)
- 3:1 for UI components and graphical elements (AA)
Meeting AA is the legal minimum in most jurisdictions. If you're new to these numbers, read WCAG Color Contrast Explained: AA vs AAA, Ratios, and When Each Matters first.
Step 1 — Identify Your Color Pairs
Before you check anything, map out every text-and-background combination in your UI:
- Body text on page background
- Headings on page background (may be large text, which has a relaxed threshold)
- Link color on page background
- Placeholder text on input background
- Button label on button background (each button variant separately)
- Badge / tag text on badge background
- Error messages on error background
- Disabled state text (exempt, but document it intentionally)
- Text on images or gradients (test multiple points)
Make a list — a simple spreadsheet or Figma annotation works. You'll run each pair through the checker.
Step 2 — Use a Real-Time Contrast Checker
The FocusFlow Color Contrast Checker is a free browser tool that requires no login or install. Here's how to use it:
- Enter your background color — type the hex code directly (e.g.,
#f8fafc) or click the color swatch to use a visual picker - Enter your text color — same approach (e.g.,
#1e293b) - Read the ratio — displayed prominently in the center (e.g.,
16.73:1) - Check the badges — four pass/fail indicators: AA Normal, AA Large, AAA Normal, AAA Large
- Use the swap button — flip background and text in one click to test the inverse
- Share your results — download a shareable 1200×630 PNG for design reviews or documentation
The tool also surfaces contrast-safe color suggestions when you're editing a field — variants of your chosen color that meet AA requirements, so you can fix a failing pair without leaving the tool.

Step 3 — Check Directly in Browser DevTools
For colors already live on a page, browser DevTools can show contrast ratios inline:
Chrome / Edge:
- Open DevTools (F12)
- Use the Element Picker (Ctrl+Shift+C / Cmd+Shift+C) to select any text element
- In the Styles panel, click the color swatch next to the
colorproperty - The color picker shows the contrast ratio against the computed background, with pass/fail icons for AA and AAA
Firefox:
- Open DevTools and go to the Accessibility panel
- Click Check for issues → Contrast — Firefox highlights every element that fails its applicable threshold
This is the fastest way to audit a page you're actively working on, since you don't need to extract hex codes manually.
Step 4 — Audit a Full Page with Automated Tools
For a first pass over an entire page, use an automated accessibility checker:
axe DevTools (Chrome extension — free tier)
Runs WCAG audits including contrast checks across the visible DOM. Under-reports (can't check text in canvas or images) but catches the majority of failures quickly.
Lighthouse (built into Chrome DevTools)
Go to DevTools → Lighthouse → run an Accessibility audit. Reports contrast failures with element selectors, making them actionable.
axe-core in CI
Add @axe-core/playwright or @axe-core/jest to your test suite to catch regressions before they reach production:
import { checkA11y } from 'axe-playwright';
test('page passes contrast checks', async ({ page }) => {
await page.goto('/');
await checkA11y(page, null, {
runOnly: { type: 'tag', values: ['wcag2aa'] }
});
});
Automated tools catch roughly 30–40% of WCAG failures. Color contrast is one area they cover well for static text, but they can't catch text over images or dynamically computed colors.
Step 5 — Review States and Interactions
Static page checks miss a lot. For each component, also verify:
- Focus state — the focus ring must have 3:1 contrast against adjacent colors (WCAG 2.2 SC 2.4.11)
- Hover state — if hover changes text or background color, check the new pair
- Error state — error text and error border colors on their backgrounds
- Dark mode — if your app has a dark theme, it's a separate set of color pairs to audit
Common Mistakes to Avoid
"Our brand blue is accessible."
Most medium blues (like the Tailwind blue-500 #3b82f6) fail 4.5:1 on white (it's only 3.0:1). Check your specific shade — don't assume.
Checking only text, not icons or borders
Input borders, icon-only buttons, and chart lines all fall under WCAG 1.4.11 Non-text Contrast (3:1). Run these through the checker too.
Checking design mocks, not computed styles
A design mock in Figma may show #64748b as the placeholder color, but CSS ::placeholder renders it differently across browsers. Check in the actual browser.
Assuming gradients average out
For text on a gradient background, find the point where contrast is lowest and check that pair. The worst case must pass.
Building Contrast Checking into Your Workflow
| Stage | Tool | Who |
|---|---|---|
| Design | Figma contrast plugin or FocusFlow Checker | Designer |
| Component build | DevTools inline picker | Developer |
| PR review | axe-core in CI tests | Automated |
| Full audit | Lighthouse + manual spot-check | QA / developer |
| Before release | axe DevTools + manual state review | QA |
The most expensive time to find a contrast failure is after shipping. The cheapest is at the color selection stage — before a design token is adopted into a component library.
Quick Checklist
- Body text passes AA (4.5:1)
- Heading text passes AA for large text (3:1 if ≥ 18px)
- Links pass AA (4.5:1) and are distinguishable from surrounding text
- Button labels pass AA on all button variants (primary, secondary, danger)
- Placeholder text passes AA (4.5:1) —
::placeholderoften fails by default - Input borders pass AA (3:1) against page background
- Focus rings visible at 3:1 against adjacent colors
- Error state text and borders pass on error backgrounds
- Dark mode color pairs audited separately