design
WCAG Contrast for SaaS Dashboards: The 5-minute Audit That Catches Most Sins
Most SaaS dashboards quietly fail WCAG contrast on the metrics, sparklines, and disabled states nobody checks. Here's the cheatsheet, the failure patterns, and a 5-minute audit you can run today.
Published 2026-05-31 · 8 min read

Your dashboard is probably failing WCAG. Mine was too.
I run a small audit on every SaaS dashboard I see. The pattern is consistent: marketing pages are usually fine. Settings pages are usually fine. The dashboard itself — the part the product actually does — fails WCAG contrast on at least one critical element about three-quarters of the time.
The usual suspects: muted secondary metrics, chart axis labels, "ghost" buttons, success-green text on white, the disabled state of the primary button. These are exactly the elements designers iterate on most, and exactly the elements that get tweaked away from the safe brand palette during sprint pressure.
This post is the 5-minute audit I run, the four contrast rules worth memorizing, and the tools — including a free contrast ratio checker — that catch the failures before a customer files an accessibility complaint.
The contrast rules, distilled
The W3C's Web Content Accessibility Guidelines define two contrast levels for text. After years of debugging real dashboards, I've reduced them to a single table that lives on a sticky note next to my monitor:
| Text type | AA (minimum) | AAA (preferred) | |---|---|---| | Body text (under 18pt regular or 14pt bold) | 4.5:1 | 7:1 | | Large text (18pt+ regular or 14pt+ bold) | 3:1 | 4.5:1 | | UI components + graphical objects (icons, focus rings, chart elements) | 3:1 | — |
These are from WCAG 2.1 Success Criterion 1.4.3 (Contrast Minimum) and 1.4.11 (Non-text Contrast). They're not negotiable for legal compliance in most jurisdictions, and they line up surprisingly well with what feels readable.
Two practical implications most teams miss:
-
Sparklines and chart strokes are UI components, not text. They fall under the 3:1 rule, but
#cbd5e1(slate-300) on white is 1.65:1. Most dashboard charts I see fail this and nobody is enforcing it. -
Disabled states are exempt from contrast requirements under SC 1.4.3 — but only if they're genuinely non-interactive. If a "disabled" button still triggers a tooltip or shows an error on click, it's interactive, and the rules apply.
The 5 patterns that fail in every dashboard I audit
After auditing dozens of SaaS UIs, these are the same five failures over and over:
1. Muted secondary metrics. "Last updated 2 hours ago" in #94a3b8 (slate-400) on a #f8fafc background. That's 3.1:1 — fails AA for body text. The fix is one shade darker (slate-500 is 4.6:1). Designers default to slate-400 because it "looks elegant"; it's also illegal.
2. Success/danger text on white. #22c55e (Tailwind green-500) on white is 2.5:1. Catastrophic failure. Use green-700 (#15803d) at 4.7:1 minimum. This trips up almost every dashboard that uses a default color framework without tuning.
3. Chart axis labels. Lines and small text in #94a3b8 — fails. Charts need at least slate-500 (4.6:1) for labels and ≥ 3:1 contrast for the lines themselves.
4. Focus rings. The trendy "no focus ring" reset breaks 2.4.7 (Focus Visible) entirely. If you've removed the default focus ring, you need a custom one with ≥ 3:1 contrast against the background. The A11y Project has a thorough guide on focus visibility that's worth reading once.
5. Hover-only contrast. A button that fails contrast at rest but passes on hover doesn't meet the criterion. The rest state is what gets audited.
The 5-minute audit
This is the workflow I run on any dashboard before shipping a redesign. Five steps, five minutes:
1. Open the page in question. Pick the busiest screen, not the empty state.
2. Take a screenshot. Drag it into a contrast checker. For each color pair you're worried about, sample the pixel values and check the ratio.
3. Generate a candidate "safe" palette using a color palette generator — even if you don't use the output, the contrast ratios it shows for each pair are a quick sanity check against your current palette.
4. Test with the OS-level "Increase contrast" accessibility setting on (macOS: System Settings → Accessibility → Display). About 8% of users have this turned on. If your "subtle" elements disappear entirely, you have a problem.
5. Run the page through an automated linter (Axe DevTools, Lighthouse, WAVE). These catch maybe 30-40% of issues but they catch the ones you'd be most embarrassed about.
This audit is not a substitute for hiring an accessibility consultant for a real product. It is enough to catch the obvious failures that ship every Friday afternoon.
Where automated tools miss things
Three failure modes automated checkers do not catch:
- Data-dependent contrast. If your "low" state is gray-300 and "high" is red-600, the contrast between them is fine — but the contrast of each individually against the background needs to be ≥ 3:1, and a checker won't know that "low" can occur on its own.
- Composite contrast. Stacked translucent overlays (the modern glassmorphism look) shift contrast based on what's behind them. Static checkers see only the foreground color.
- State changes that change context. A status pill that turns from gray to amber doesn't change in contrast against the background — it changes in meaning. Color-blind users may miss the change entirely. The Smashing Magazine guide on dashboard accessibility patterns covers this kind of multi-channel signaling well.
The fix for all three is the same: pair every color signal with a non-color cue (icon, label, weight). Belt and suspenders.
A pragmatic palette
If you want a starting point that nearly always passes AA when used correctly:
- Body text: slate-700 (
#334155) on slate-50 (#f8fafc) = 10.8:1 - Secondary text: slate-500 (
#64748b) = 5.3:1 (passes AA body, fails AAA) - Accent on white: anything in the 600 weight range of the major frameworks
- Success: green-700 (
#15803d) = 4.7:1 - Danger: red-700 (
#b91c1c) = 6.0:1
Run any custom values through a color contrast checker before you ship. Two minutes saved arguing with a designer is worth two hours not spent re-tuning the palette after a customer files an a11y complaint.
The mindset shift
Most contrast failures aren't designers ignoring accessibility — they're designers chasing "elegance" and not realizing the elegant choice is also the illegible one. The fix is to put a contrast check next to every color decision in the design system, not at the end as a compliance step.
If you do nothing else from this post: open your current dashboard, pull up a color contrast checker, and check the three most muted text colors. You will almost certainly find at least one failure. Spend the 10 minutes to fix it before the next design review. It is the single highest-ROI accessibility task on the board.
Sources
- W3C — WCAG 2.1 Success Criterion 1.4.3: Contrast (Minimum)
- The A11y Project — Never remove CSS outlines
- Smashing Magazine — Accessibility best practices for tabs and dashboards