Picking colors for dark mode feels like throwing darts blindfolded. The brand blue that looked perfect on white is invisible on dark. The muted gray that worked for secondary text now screams at full brightness. And every 'accessible color palette' article on the internet assumes a white background.
This one doesn't. Every color combination below was tested against dark backgrounds — #121212 (near-black), #0F172A (dark navy), #1E1E2E (dark slate), and #000000 (OLED black). Each pair includes the exact contrast ratio, WCAG verdict, and where to use it.
The Testing Method
Every combination was run through the WCAG 2.1 contrast formula against four dark backgrounds. The results show the lowest ratio across all four — meaning if it passes here, it passes on any standard dark mode background.
Rating key:
Body Text Combinations (The Foundation)
Body text is what users read for minutes at a time. In dark mode, aim for AAA (7:1+) — the halation effect makes even mathematically identical ratios feel lower.
1. #E5E7EB on #121212 → 15.8:1 🟢 AAA. The default. Slightly off-white to reduce glare. Works everywhere. Use for all body copy in dark mode.
2. #D1D5DB on #0F172A → 13.2:1 🟢 AAA. Tailwind's dark mode text. Slightly warmer than #E5E7EB. Excellent for reading-heavy dark mode UIs.
3. #F1F5F9 on #121212 → 16.5:1 🟢 AAA. Cooler, crisper white. Better for data-heavy interfaces where text needs to feel precise. Avoid in long-form reading — the cool temperature increases eye strain over time.
4. #C8CDD4 on #1A1A2E → 12.1:1 🟢 AAA. Warmer slate text. Design tools and creative apps often use this pair — it feels premium without sacrificing readability.
5. #E8E8F0 on #0F0F1A → 15.2:1 🟢 AAA. Slightly purple-tinted text on a deep indigo background. Creative agency dark mode. Reads beautifully at any size.
Secondary / Muted Text
Secondary text still needs 4.5:1 (AA). Many dark mode designs push muted text too light — #6B7280 on #121212 is only 5.5:1 (passes, but barely). Go darker than you think.
6. #9CA3AF on #121212 → 8.5:1 🟢 AAA. The sweet spot for muted text. Visibly lighter than body text, still AAA. Use for timestamps, captions, metadata.
7. #94A3B8 on #0F172A → 7.5:1 🟢 AAA. Cool gray muted text on navy. Works for card descriptions and secondary labels.
8. #A1A1AA on #18181B → 7.4:1 🟢 AAA. Zinc palette muted text. Slightly warmer than slate. Good for footer links and legal text.
Brand Accent Combinations (The Hard Part)
This is where most dark modes die. Brand colors optimized for white backgrounds need 20-40% more lightness to work on dark. Here are 10 tested brand-color equivalents that preserve the original hue while passing WCAG AA on dark backgrounds.
Blues
9. #60A5FA (Light Blue) on #121212 → 9.8:1 🟢 AAA. The dark mode hyperlink blue. Replaces #3B82F6 (which fails at 2.3:1 on dark). Still reads as a vibrant blue. Use for all links and interactive text.
10. #93C5FD (Softer Blue) on #0F172A → 14.2:1 🟢 AAA. A gentler blue for dark navy backgrounds. Better for information architecture links (breadcrumbs, category tags) than #60A5FA which is better for actionable links.
11. #38BDF8 (Sky Blue) on #121212 → 10.5:1 🟢 AAA. Cyan-leaning blue. Feels modern and technical. Great for developer tools, dashboards, and CLI-inspired interfaces.
Greens
12. #34D399 (Emerald) on #121212 → 10.2:1 🟢 AAA. The dark mode success green. Replaces #059669 (fails at 2.8:1). Bright enough to feel positive, dark enough to read. Use for success states, confirmations, and positive metrics.
13. #86EFAC (Mint) on #0F172A → 15.8:1 🟢 AAA. Softer green. Better for non-urgent positive indicators like 'Online now' badges or completion percentages.
14. #4ADE80 (Vibrant Green) on #121212 → 12.4:1 🟢 AAA. Brighter, more energetic green. Use sparingly — for primary CTAs and 'Get Started' buttons. Too much of this green becomes overwhelming.
Reds & Warnings
Test these combinations yourself. Enter any color pair and see WCAG + APCA results instantly on dark backgrounds.
Test Dark Mode Colors15. #F87171 (Soft Red) on #121212 → 9.5:1 🟢 AAA. The dark mode error red. Replaces #DC2626 (fails at 2.5:1). Soft enough to not vibrate against dark backgrounds, red enough to convey urgency. Use for error messages and destructive actions.
16. #FCA5A5 (Lighter Red) on #0F172A → 13.8:1 🟢 AAA. A gentler red for inline validation errors. Use when the error needs to be visible but not alarming.
17. #FBBF24 (Amber) on #121212 → 12.8:1 🟢 AAA. Dark mode warning. One of the rare colors that's actually more readable in dark mode than light. Use for warning states, 'needs attention' badges, and caution indicators.
18. #F59E0B (Dark Amber) on #0F172A → 9.2:1 🟢 AAA. Slightly darker amber for navies. Better when you need a warning color that doesn't dominate the page.
Purples & Pinks
19. #C084FC (Soft Purple) on #121212 → 10.5:1 🟢 AAA. Dark mode brand purple. Replaces #7C3AED (fails at 2.1:1). Use for premium indicators, feature highlights, and creative brand accents.
20. #E9D5FF (Lavender) on #0F172A → 17.2:1 🟢 AAA. Extremely light purple for dark navy. Works beautifully for 'new' badges, beta tags, and category labels.
21. #F9A8D4 (Soft Pink) on #121212 → 10.8:1 🟢 AAA. The dark mode pink that doesn't feel like a Valentine's card. Use for lifestyle brands, beauty products, and creative portfolios.
UI Element Combinations (The Invisible Failures)
Text contrast gets all the attention, but UI elements — borders, icons, focus rings — cause the most dark mode accessibility failures. The 3:1 non-text contrast requirement (SC 1.4.11) is where dark mode cheating happens.
Borders & Dividers
22. #4B5563 on #111827 → 3.2:1 🟡 Passes non-text contrast. The minimum viable dark mode border. Anything lighter than this will fail 3:1. Use for card borders, input outlines, and section dividers.
23. #6B7280 on #121212 → 5.8:1 🟢 Exceeds non-text contrast. A more visible border. Better for form inputs where the boundary needs to be unambiguous.
24. #374151 on #0F172A → 2.1:1 🔴 Fails non-text contrast. This is what most dark mode UIs ship — and it's invisible. Never use #374151 or lighter as a UI boundary on dark backgrounds.
Focus Indicators
25. #60A5FA (2px solid) on #121212 → 9.8:1 🟢 AAA (as non-text contrast). A blue focus ring that's immediately visible. The gold standard for dark mode focus indicators.
26. #FBBF24 (2px solid) on #0F172A → 12.8:1 🟢 AAA. Amber focus ring. Higher visibility than blue on some displays. Good for high-contrast mode compatibility.
27. #FFFFFF (2px solid) on #121212 → 21:1 🟢 AAA. White focus ring. Maximum visibility. Can feel harsh — pair with a 2px gap from the element edge for a cleaner look.
Icons
28. #D1D5DB on #121212 → 15.8:1 🟢 AAA. Standard dark mode icon color. Same as body text — icons should match text weight in dark mode.
29. #9CA3AF on #0F172A → 8.5:1 🟢 AAA. Muted icons (secondary actions, decorative icons). One shade lighter than the primary icon color.
Special Cases
30. #FFFFFF on #000000 → 21:1 🟢 AAA. OLED maximum contrast. Passes everything — but use cautiously. Pure white on pure black causes the strongest halation and is uncomfortable for users with astigmatism. Reserve for short, large text (hero headings, logo marks) — never for body copy.
The Dark Mode Palette Quick Reference
Here's the TL;DR — one token, two colors. Copy these CSS custom properties for instant dark mode coverage:
```css
:root {
/ Light mode (your existing palette) /
--text-primary: #1E293B;
--text-secondary: #64748B;
--bg-primary: #FFFFFF;
--accent: #2563EB;
--success: #059669;
--error: #DC2626;
--border: #D1D5DB;
}
[data-theme='dark'],
@media (prefers-color-scheme: dark) {
:root {
--text-primary: #E5E7EB; / was #1E293B → 15.8:1 AAA /
--text-secondary: #9CA3AF; / was #64748B → 8.5:1 AAA /
--bg-primary: #121212; / was #FFFFFF /
--accent: #60A5FA; / was #2563EB → 9.8:1 AAA /
--success: #34D399; / was #059669 → 10.2:1 AAA /
--error: #F87171; / was #DC2626 → 9.5:1 AAA /
--border: #4B5563; / was #D1D5DB → 3.2:1 on dark /
}
}
```
Three Principles for Dark Mode Color Selection
After testing hundreds of dark mode color pairs, three patterns emerge:
1. Lighten by 20-40%, keep the hue. Every brand color that works in light mode has a dark mode equivalent 20-40% lighter. The hue stays identical. The saturation may shift slightly (usually down 5-10% to prevent neon effects). Use our HSL Contrast Checker to find the exact lightness value that hits your target ratio.
2. Dark mode = higher contrast, not lower. The instinct is to make dark mode 'moody' with low contrast. Fight this instinct. Dark mode should have higher contrast than light mode because halation makes the same ratio perceptually lower. Target AAA (7:1) for body text, not just AA (4.5:1).
3. Test borders first, text second. Text contrast failures are obvious — bad text looks bad. Border failures are invisible — until a keyboard user can't see the focus ring on your form. Audit non-text contrast before text contrast. Our Icon Contrast Checker verifies UI elements against the 3:1 standard.
How to Test These Combinations Yourself
Don't copy-paste blindly. Every dark mode background is slightly different, and your specific hex codes need verification.
Fastest: Open our Dark Mode Contrast Checker, enter your background and foreground hex codes, and see the WCAG AA/AAA verdict + APCA score instantly.
Most thorough: Install the free Chrome Extension, switch your site to dark mode, and click scan. It walks every visible text element and reports all contrast violations in one list — sorted worst-first. Click any violation to highlight it on the page.
At design stage: Use the Figma Plugin to check contrast directly on your dark mode frames. Select any text layer and see instant WCAG + APCA results without leaving your canvas.
Dark mode color selection isn't harder than light mode — it's just different. Use these 30 combinations as a starting point, verify with tools, and build a dark mode palette that's as readable as it is beautiful.