The Ultimate WCAG Color Guide for Designers (2.1, 2.2, 3.0 + APCA)
WCAG (Web Content Accessibility Guidelines) is the standard most accessibility laws cite. WCAG 2.1 is in force in the US (ADA), EU (EAA, June 2025), UK, Canada (AODA) and Australia. WCAG 2.2 was published October 2023 and adds nine new criteria. WCAG 3.0 is in draft and will adopt APCA contrast.
This guide covers everything you need to know about color in WCAG: every contrast threshold and where it applies, how the math actually works, the upcoming APCA standard, an audit checklist you can run on any site, and code examples for the most common compliance fixes.
It is written for designers and developers shipping production work, not for legal compliance officers. The legal nuance is real but secondary - if you ship to the standards below, the audits take care of themselves.
The complete WCAG contrast matrix
WCAG 2.1 defines three conformance levels (A, AA, AAA) and color contrast appears in five success criteria across them:
- 1.4.3 Contrast (Minimum) - AA - body text 4.5:1, large text 3:1.
- 1.4.6 Contrast (Enhanced) - AAA - body text 7:1, large text 4.5:1.
- 1.4.11 Non-Text Contrast - AA - UI components and meaningful graphics 3:1 against adjacent colors.
- 1.4.12 Text Spacing - AA - layout must not break when users override line-height/spacing.
- 1.4.13 Content on Hover or Focus - AA - tooltip/menu must remain readable when revealed.
WCAG 2.2 adds:
- 2.4.11 Focus Not Obscured (Minimum) - AA - focused element must not be entirely hidden.
- 2.5.8 Target Size (Minimum) - AA - interactive targets 24x24 CSS pixels minimum (with exceptions).
AA is the legal floor in most jurisdictions. AAA is recommended for users with low vision and is achievable for most text but rarely required.
How contrast is actually calculated
The WCAG formula uses relative luminance L computed from sRGB:
// 1. Linearize each channel
function linearize(c) {
c /= 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
}
// 2. Compute relative luminance
function luminance(r, g, b) {
return 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b);
}
// 3. Contrast ratio - lighter / darker, +0.05 floor
function contrast(rgb1, rgb2) {
const L1 = luminance(...rgb1);
const L2 = luminance(...rgb2);
const lighter = Math.max(L1, L2);
const darker = Math.min(L1, L2);
return (lighter + 0.05) / (darker + 0.05);
}The 0.7152 weight on green reflects human vision sensitivity. White on black scores 21:1, the maximum. Same color on itself scores 1:1.
You almost never compute this by hand - browser DevTools, Stark, Polypane, and our /contrast tool report it instantly.
What "large text" actually means
WCAG defines large text as: 18pt and above (or 14pt and above when bold). In CSS pixels at default zoom, that is roughly 24px regular or 19px bold.
Large text only needs 3:1 (AA) or 4.5:1 (AAA) instead of 4.5:1 / 7:1. The relaxation exists because larger glyphs have more visible pixels and are easier to read at lower contrast.
In practice: headlines, hero copy, subtitles, and large call-to-action buttons can use this exception. Body paragraphs, captions, form labels, navigation links and table cells cannot.
Non-text contrast (1.4.11): the most-missed criterion
Most teams check text contrast and stop. WCAG 1.4.11 also requires 3:1 contrast for any non-text component that conveys meaning:
- Form input borders (so users can find the input).
- Focus rings (so keyboard users can see where they are).
- Active state indicators (toggle on/off, tab selected).
- Icons that convey status (warning, error, success).
- Chart elements where color is the only differentiator.
- Hover/focus state changes that signal interactivity.
A common failure: a `border: 1px solid #d4d4d4` form input on a `#ffffff` background scores 1.6:1 - well below the required 3:1. Users with low vision cannot see where the input is. Fix: darken the border to at least `#949494`.
Color-only signals (1.4.1)
WCAG 1.4.1 prohibits using color as the only means of conveying information. The classic violation: marking errors with red text on a form. Color-blind users see no difference between the error field and the others.
The fix is to pair color with at least one of: an icon, a text label, a pattern, or a positional cue.
// Bad - color only
<input className="border-red-500" />
// Good - color + icon + text label + aria-invalid
<div>
<label htmlFor="email">Email</label>
<input id="email" aria-invalid="true" aria-describedby="email-error" className="border-red-500" />
<p id="email-error" className="text-red-700 flex items-center gap-1.5">
<AlertCircle size={14} aria-hidden /> Please enter a valid email.
</p>
</div>This same rule applies to data visualization (always include direct labels or patterns alongside color), status indicators, link styling (always underline links in body text), and required-field markers.
APCA: the next standard
WCAG 2.1 contrast was developed in the 1990s based on CRT monitor research. It systematically over-rates dark color combinations and under-rates light ones. APCA (Accessible Perceptual Contrast Algorithm) was designed by Andrew Somers to fix this and is the planned contrast model for WCAG 3.0.
APCA scores from 0 to about 108 (positive for dark text on light, negative for light on dark). The required score depends on font weight and size:
- Lc 90 - body text gold standard (low vision support).
- Lc 75 - body text minimum (replaces WCAG 4.5:1).
- Lc 60 - headline minimum (replaces WCAG 3:1 for large text).
- Lc 45 - large or bold display text.
- Lc 30 - non-essential or decorative.
APCA is already used internally by GitHub Primer, Atlassian, BBC Sounds, and many others. WCAG 2 compliance still needs the WCAG ratio test. ColorUI’s /contrast tool reports both so you can ship to today’s standard while designing toward APCA.
Common color failures and how to fix them
After auditing dozens of design systems, these are the seven failures we see again and again:
- 1. Placeholder text at #999 on #fff (3.5:1) - fails AA. Fix: #757575 (4.6:1) or remove placeholder copy that conveys instructions.
- 2. Brand color used for both buttons and body links - the color was tuned for buttons (high contrast on white) but the same color on a paragraph fails AA. Fix: separate link color or underline for differentiation.
- 3. Disabled buttons that look identical to enabled - users cannot tell they are disabled. Fix: keep enough contrast to be visible (3:1 minimum) and add aria-disabled.
- 4. White-on-orange CTAs (red/orange + white usually fails 4.5:1). Fix: darken the orange or use white on a darker brand variant.
- 5. Light gray dividers and form borders at 1.5-2:1 - fail 1.4.11. Fix: darken to at least 3:1 against the surface.
- 6. Focus rings the same color as the brand button - the ring disappears on hover/active. Fix: use a high-contrast ring color (`outline: 2px solid currentColor; outline-offset: 2px`).
- 7. Dark mode text in pure white on pure black - causes halation; dark mode tokens should use ~#0a0a0f surface and ~#e5e5e7 text, not #000/#fff.
WCAG audit checklist
Run this on every page before shipping. It catches 95% of color-related violations:
- ☐ All body text 4.5:1 or higher against its background (1.4.3).
- ☐ All headlines 3:1 or higher (1.4.3 large text exception).
- ☐ All form inputs have a visible border at 3:1 against the page (1.4.11).
- ☐ Focus rings visible at 3:1 against the focused element AND against the page (1.4.11).
- ☐ Status messages use color + icon + text label (1.4.1).
- ☐ Body links visually distinct from body text without relying on color alone (1.4.1).
- ☐ Active/selected state visible without color-only signal (1.4.1).
- ☐ Charts include direct labels or patterns - not just legends (1.4.1).
- ☐ Disabled controls visible at 3:1 against page AND aria-disabled set (1.4.11).
- ☐ Tested in DevTools color-blindness simulator (deuteranopia covers ~6% of men).
- ☐ Tested at 200% zoom - text still readable, no horizontal scrolling.
- ☐ Tested in dark mode if supported.
- ☐ Run automated audit (axe DevTools, Lighthouse, WAVE).
Tools we recommend
- Browser DevTools - Chrome and Firefox both ship a contrast picker; Chrome shows APCA when you toggle "AAA - APCA" in the color picker.
- axe DevTools (free Chrome extension) - automated WCAG audit catches 30-40% of violations.
- Lighthouse - built into Chrome DevTools; runs axe under the hood.
- Stark for Figma / Sketch - in-design contrast checking before code.
- Polypane - browser for designers with built-in contrast and color-blindness simulation.
- WAVE (WebAIM) - free browser extension for full-page audits.
- ColorUI /contrast - WCAG + APCA in one view, with token-aware suggestions.
- ColorUI /fix-a11y - paste a failing palette, get a passing variant.
Legal context (high level)
This is not legal advice, but the practical landscape: in the US, the Department of Justice has confirmed the ADA applies to public-facing websites, citing WCAG 2.1 AA as the conformance standard. The European Accessibility Act takes effect June 2025 and covers most consumer-facing digital services in the EU. The UK Public Sector Bodies Accessibility Regulations 2018 require AA for public-sector sites.
Lawsuits in the US have steadily climbed (~4,000 ADA-related digital accessibility cases per year). Most settle. The cheapest fix is shipping to AA from day one.
For private-sector US companies: WCAG 2.1 AA is the de-facto safe harbor. Going beyond (AA + APCA design targets) reduces remediation cost and improves usability for all users, not just those with disabilities.
Going further
If you have time for further reading:
- WCAG 2.1 official spec - w3.org/TR/WCAG21
- WCAG 2.2 official spec - w3.org/TR/WCAG22
- APCA spec and rationale - apcacontrast.com
- WAI tutorials - w3.org/WAI/tutorials
- Inclusive Components by Heydon Pickering (book) - the modern HTML accessibility reference.
- Refactoring UI by Steve Schoger and Adam Wathan (book) - color-design chapters complement this guide.
Try the related tools
Frequently asked questions
Do I have to comply with WCAG?
In the US (ADA), EU (EAA, in force June 2025), UK, Canada (AODA), Australia and many other jurisdictions, public-facing sites are expected to meet WCAG 2.1 AA. Many private companies adopt it voluntarily to reduce litigation risk and improve usability.
Should I use WCAG 2.1 or 2.2?
Ship to 2.2 if you can - it is a strict superset of 2.1 and will be cited in new regulations. The contrast formulas are identical between 2.1 and 2.2.
Is APCA legally required?
Not yet. WCAG 3.0 (which will adopt APCA) is still in draft. Use APCA as a design target alongside WCAG ratios for the foreseeable future.
Does dark mode have different WCAG rules?
No - the same ratios apply. But WCAG 2.1’s formula systematically over-rates dark combinations, so APCA is especially valuable for evaluating dark-mode designs.
Can I use a color picker that shows both WCAG and APCA?
Yes. Chrome DevTools and ColorUI /contrast both display both. APCA picks more accurately reflect what users actually perceive.
How often do I need to re-audit?
On every visual change to a shipping component, plus a quarterly full-page audit. Component-library teams should gate every PR with axe + a contrast assertion.