Introduction
Most developers know about contrast ratios — 4.5:1 for normal text, 3:1 for large text. But color accessibility goes much further. About 8% of men and 0.5% of women have some form of color vision deficiency. If your UI relies on color alone to convey information, these users miss critical context.
Beyond color blindness, consider low vision, different displays, and environments (bright sunlight). Accessible color design means every piece of color-encoded information has a non-color alternative — text labels, icons, patterns, or position.
This guide covers color blindness types, designing for color independence, testing tools, and building inclusive color palettes.
Key Concepts
Types of Color Vision Deficiency
- Deuteranopia (green-blind) — Most common. Red and green look similar. ~5% of men.
- Protanopia (red-blind) — Red appears dark. Red/green confusion. ~1% of men.
- Tritanopia (blue-blind) — Blue and yellow confusion. Rare (~0.003%).
- Achromatopsia — Complete color blindness (sees only grayscale). Very rare.
The Color Independence Principle
// ❌ Bad: Color is the only indicator
<span style={{ color: error ? 'red' : 'green' }}>{status}</span>
// ✅ Good: Color + text + icon
<span style={{ color: error ? 'red' : 'green' }}>
{error ? '❌ Error' : '✅ Success'}: {status}
</span>
// ❌ Bad: Form error indicated only by red border
<input style={{ borderColor: 'red' }} />
// ✅ Good: Red border + error icon + error message
<div>
<input aria-invalid="true" aria-describedby="email-error" style={{ borderColor: 'red' }} />
<p id="email-error" className="text-red-500">⚠️ Please enter a valid email</p>
</div>
Practical Examples
1. Accessible Status Badges
function StatusBadge({ status }: { status: 'active' | 'warning' | 'error' | 'inactive' }) {
const config = {
active: { color: 'bg-green-100 text-green-800', icon: '●', label: 'Active' },
warning: { color: 'bg-yellow-100 text-yellow-800', icon: '▲', label: 'Warning' },
error: { color: 'bg-red-100 text-red-800', icon: '✕', label: 'Error' },
inactive: { color: 'bg-gray-100 text-gray-800', icon: '○', label: 'Inactive' },
};
const { color, icon, label } = config[status];
return (
<span className={`px-2 py-1 rounded-full text-sm font-medium ${color}`}>
{icon} {label}
</span>
);
}
2. Accessible Data Visualization
// Charts: Don't rely on color alone
// ✅ Use patterns, labels, and shapes alongside colors
// For line charts: different line styles (solid, dashed, dotted)
const datasets = [
{ label: 'Revenue', color: '#3B82F6', dash: 'solid', marker: 'circle' },
{ label: 'Expenses', color: '#EF4444', dash: 'dashed', marker: 'square' },
{ label: 'Profit', color: '#10B981', dash: 'dotted', marker: 'triangle' },
];
// For bar charts: add patterns or direct labels
// For pie charts: add labels on or next to each slice
3. Testing Color Independence
// Chrome DevTools: Rendering → Emulate vision deficiencies
// Options: Deuteranopia, Protanopia, Tritanopia, Achromatopsia
// Quick test: Convert screenshot to grayscale
// If you can still understand the UI, it passes the color independence test
// CSS grayscale test:
html { filter: grayscale(100%); }
// Tools:
// - Chrome DevTools vision emulation
// - Stark (Figma plugin)
// - Color Oracle (desktop app)
// - sim-daltonism (macOS)
Best Practices
- ✅ Always provide a non-color indicator: text, icons, patterns, or position
- ✅ Test with color blindness simulators in Chrome DevTools
- ✅ Use the grayscale test — if UI is understandable in grayscale, it's color-independent
- ✅ Choose palettes that are distinguishable for common deficiencies (avoid pure red/green pairs)
- ✅ Use distinct shapes in charts alongside colors
- ❌ Don't use red/green as the only differentiator (success/error)
- ❌ Don't use color alone for required field indicators — add an asterisk or text
Common Pitfalls
- Green checkmarks and red X marks as the only indicators — add text labels
- Heat maps with no alternative data representation — provide a data table option
- Link text that's only distinguished from body text by color — add underline
- Assuming passing WCAG contrast means it's color-accessible — contrast and color independence are separate
Related Guides
- WCAG Practical Guide — Color-related criteria (1.4.1, 1.4.3, 1.4.11)
- Design Tokens Complete Guide — Building accessible color palettes as tokens
- Theming with CSS Variables — Ensuring theme colors are accessible
- Accessibility Testing Tools — Automated color accessibility testing