Low contrast text is the single most prevalent accessibility defect on the web, and it directly excludes users with low vision, color blindness, or age-related vision changes without any assistive technology involved. WCAG 2.2 SC 1.4.3 (Level AA) requires 4.5:1 contrast for normal text and 3:1 for large text (18pt+ or 14pt+ bold). SC 1.4.1 bars using color as the only visual means of conveying information. Section 508 2018 Refresh 502.3.3 incorporates these thresholds directly. Agencies and contractors that fail contrast requirements face procurement disqualification and Section 508 complaint proceedings.
Critical because insufficient contrast excludes users with low vision without requiring any assistive technology failure—it is a direct usability barrier affecting the largest share of users with visual disabilities.
Check every foreground/background color pair using WebAIM Contrast Checker or the browser's Accessibility Inspector. Normal text must reach 4.5:1; large text (≥18pt or ≥14pt bold) must reach 3:1. Update src/app/globals.css or your Tailwind theme:
/* Normal body text — ~12:1 contrast */
body { color: #1a1a1a; background-color: #ffffff; }
/* Large headings — 3:1 minimum met at ~7:1 */
h1, h2 { color: #4a4a4a; }
/* Placeholder text often fails — set explicitly */
::placeholder { color: #767676; } /* 4.54:1 on white */
When conveying state through color, always pair it with a non-color indicator:
{hasError && (
<div className="error-message">
<AlertIcon aria-hidden="true" />
<span>This field is required</span>
</div>
)}
gov-section-508.wcag-core.color-contrastcritical"Input validation error uses red color (#ff0000) only, with no error icon or error text label. Placeholder text has contrast ratio 2.8:1 against white background (needs 4.5:1)." or "Status badge colors: orange (warning) with contrast 3.2:1 against white (needs 4.5:1), green (success) with contrast 3.1:1"/* Normal text: 4.5:1 contrast */
body { color: #333333; background: #ffffff; } /* Contrast ~12:1 */
/* Large text (18pt+): 3:1 contrast */
.large-text { color: #666666; background: #ffffff; } /* Contrast ~7:1 */
Use a contrast checker tool (e.g., WebAIM, Contrast Ratio) to verify. When conveying state or meaning through color, always add supporting text or icons:
{hasError && (
<div style={{ color: '#d32f2f' }}>
<ErrorIcon />
<span>This field is required</span>
</div>
)}