Dark Mode Done Right: A Design Guide
Dark mode is not just "invert the colors." Done poorly, it causes eye strain, hides content, and breaks visual hierarchy. Done well, it is elegant, reduces eye fatigue in low light, and can even save battery on OLED screens.
Choosing a Dark Color Palette
The biggest mistake is using pure black (#000000) as your background. Pure black creates harsh contrast with white text and feels unnatural. Instead, use a dark gray:
<!-- Avoid pure black -->
<div class="bg-black text-white">Too harsh</div>
<!-- Better: dark zinc -->
<div class="bg-zinc-950 text-zinc-50">Much easier on the eyes</div>
<!-- Even better: slightly warm dark -->
<div class="bg-[#0a0a0b] text-zinc-100">Subtle warmth</div>Build your dark palette from a single base gray scale. Tailwind's zinc scale works well: zinc-950 for backgrounds, zinc-900 for elevated surfaces, zinc-800 for borders, zinc-400 for secondary text, and zinc-100 for primary text.
Contrast Ratios Still Apply
Dark mode does not exempt you from WCAG contrast requirements. Light gray text on dark gray backgrounds can easily fail the 4.5:1 ratio. Test every text color:
- Primary text (
zinc-100onzinc-950): 15.4:1 ratio. Excellent. - Secondary text (
zinc-400onzinc-950): 7.1:1 ratio. Good. - Muted text (
zinc-600onzinc-950): 3.3:1 ratio. Fails for body text, okay for large headings only.
Elevated Surfaces
In light mode, you create depth with shadows. In dark mode, shadows are invisible against dark backgrounds. Instead, use lighter background colors for elevated elements:
<!-- Light mode: shadow for depth -->
<div class="bg-white shadow-lg rounded-xl p-6">
Card content
</div>
<!-- Dark mode: lighter bg for depth -->
<div class="bg-white dark:bg-zinc-900 shadow-lg dark:shadow-none rounded-xl border border-transparent dark:border-zinc-800 p-6">
Card content
</div>Each layer up gets slightly lighter: zinc-950 (page) → zinc-900 (card) → zinc-800 (nested element). This creates a clear visual hierarchy without shadows. Our dark pricing component demonstrates this layering approach.
The CSS Variables Approach
Hardcoding dark: variants on every element is tedious and error-prone. A better approach uses CSS custom properties:
:root {
--background: 0 0% 100%;
--foreground: 240 10% 4%;
--card: 0 0% 100%;
--border: 240 6% 90%;
}
.dark {
--background: 240 10% 4%;
--foreground: 0 0% 98%;
--card: 240 6% 10%;
--border: 240 4% 16%;
}Then in Tailwind, reference these variables. Change the theme once and every component updates automatically. This is the approach UI Drop uses across all components.
Component Adaptation Gotchas
Some components need more than a palette swap:
Images. Bright images on dark backgrounds feel jarring. Consider reducing brightness slightly with dark:brightness-90 or adding a subtle overlay.
Borders. Light mode borders (border-zinc-200) become invisible on dark backgrounds. Use dark:border-zinc-800 explicitly.
Status colors. Green, red, and yellow indicators need different shades in dark mode. A bright green that works on white looks neon on dark backgrounds. Desaturate slightly.
Charts and graphs. Data visualization colors often need a complete rethink for dark mode. Lighter, more saturated colors work better on dark backgrounds.
Common Mistakes
Forgetting scrollbar styling. A bright white scrollbar on a dark page is distracting. Use scrollbar-color in CSS or style the webkit scrollbar.
Not testing transitions. If your theme toggle animates, make sure it does not flash white during the switch. Load the theme preference before rendering — UI Drop uses a script in <head> to prevent flash of incorrect theme.
Ignoring system preference. Respect prefers-color-scheme: dark as the default when users have not made an explicit choice.
Browse our components in dark mode to see these principles applied. Try the dark cinematic hero and the glass card for good examples of dark-mode-first design.
Related Articles
Building Accessible UI Components from Scratch
Why accessibility matters and how to build components that work for everyone, with practical ARIA tips.
Read more →50 Essential Tailwind CSS Component Patterns
A reference guide covering the most common Tailwind CSS patterns for cards, buttons, forms, modals, and more.
Read more →Pricing Page Design Patterns That Convert
A deep dive into pricing table designs that drive conversions, including toggle switches, comparison tables, and trust signals.
Read more →