Test color contrast ratios
Normal text: 4.5:1 ratio. Large text (18pt+ or 14pt+ bold): 3:1 ratio. WCAG 1.4.6 (Level AAA) requires 7:1 for normal text.
Text and buttons
Regular body text (#D1D5DB - 1.6:1 ❌)
Secondary text (#9CA3AF - 2.7:1 ❌)
Link text (#93C5FD - 2.3:1 ❌)💡 Note: Disabled elements are exempt from contrast requirements, but consider using other visual cues (opacity, icons).
Test your colors
Sample Text Preview
The quick brown fox jumps over the lazy dog
Contrast Ratio
Normal text
Enhanced
Level AA and AAA
Testing hints
import AxeBuilder from '@axe-core/playwright';
// Check all color contrast violations
const results = await new AxeBuilder({ page })
.withRules(['color-contrast'])
.analyze();
for (const violation of results.violations) {
console.log('Contrast issues:');
for (const node of violation.nodes) {
console.log({
element: node.target,
issue: node.failureSummary
});
}
}
// Verify specific element contrast
const button = page.getByTestId('button-example');
const styles = await button.evaluate(el => ({
color: getComputedStyle(el).color,
bg: getComputedStyle(el).backgroundColor
}));// Calculate contrast ratio programmatically
function getContrastRatio(fg: string, bg: string) {
const luminance = (hex: string) => {
const rgb = parseInt(hex.slice(1), 16);
const r = ((rgb >> 16) & 0xff) / 255;
const g = ((rgb >> 8) & 0xff) / 255;
const b = (rgb & 0xff) / 255;
const linear = (c: number) =>
c <= 0.03928
? c / 12.92
: Math.pow((c + 0.055) / 1.055, 2.4);
return 0.2126 * linear(r)
+ 0.7152 * linear(g)
+ 0.0722 * linear(b);
};
const l1 = luminance(fg);
const l2 = luminance(bg);
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}Automation hints
withRules(['color-contrast'])getComputedStyle(el).color and backgroundColor