Designing for dark mode on mobile UI isn’t an optional feature anymore. It’s a basic expectation that really affects user experience and device battery life. With so many people flipping their OS to a darker interface, you have to know how to implement dark mode properly or your app will feel dated and less accessible.
Key Takeaways
- Use semantic color names in your design tokens (think
primary-backgroundoron-surface) so you can switch themes consistently without breaking everything. - Get a contrast checker into your workflow from day one. You need to hit at least 4.5:1 for normal text and 3:1 for large text per WCAG 2.1, so don’t eyeball it.
- You have to test your dark mode on real phones in different lighting situations, especially a dark room. That’s the only way you’ll spot glare or readability problems that simulators miss.
- Stick to dark grays like
#121212or#1A1A1Afor your backgrounds instead of pure black (#000000). It’s easier on the eyes and avoids that weird “blooming” effect on OLEDs. - Always give users a toggle in the settings to turn dark mode on or off, even if you’re already syncing with their system preference. They expect that control.
1. Establish a Semantic Color System
A solid dark mode implementation absolutely begins with a semantic color system. Don’t just make a list of light mode hex codes and their dark mode twins. Define your colors based on what they *do*. This approach is what keeps your design system from becoming a total mess when you eventually add more themes or hand it off to a new developer.
So instead of having a variable like `white` set to #FFFFFF for a background, you’d define tokens with names like background-primary, surface-primary, or text-on-surface. In your light theme, background-primary might be #F5F5F5 and its text #212121. Then for the dark theme, you just redefine background-primary to something like #1A1A1A and its text to #E0E0E0 without touching a single component.
Modern tools like Figma and Sketch are built for this. In Figma, you can set up your colors as “Styles” and then build out different themes that point your semantic tokens (like `text-on-background`) to specific hex values. It makes flipping between light and dark mode a one-click theme swap instead of a nightmare of hunting down and changing every color instance by hand.
Pro Tip: Start Dark, Then Go Light
A lot of designers actually find it easier to design the dark theme first. It forces you to think about contrast and readability from a tougher starting point. Once you’ve nailed the dark theme, making a light version that works is often way simpler. It’s definitely an opinionated workflow, but it tends to produce more accessible designs.
Common Mistake: Direct Inversion
The most frequent error is just inverting the colors. Slapping pure white text (#FFFFFF) on a pure black background (#000000) is a recipe for eye strain, and on OLED screens, it creates a “blooming” effect where the contrast is just too harsh. You’re almost always better off using dark grays for your main backgrounds (like #121212, #1E1E1E, or #212121) and off-whites for your text (#E0E0E0, #F0F0F0).
2. Ensure Adequate Contrast and Readability
Accessibility can’t be an afterthought in dark mode. The Web Content Accessibility Guidelines (WCAG) 2.1 lay out the minimums: for normal text, your contrast ratio against the background needs to be at least 4.5:1. For large text (which they define as 18pt or 14pt bold), you can get away with 3:1. These aren’t just suggestions, and they apply just as much to dark themes.
Use a contrast checker right in your design tool or a web-based one like WebAIM’s Contrast Checker. For example, you might think a text color of #A0A0A0 looks fine on your #1A1A1A dark background, but running it through a checker will show you it fails the 4.5:1 test. To pass, the text would probably need to be bumped up to something like #C0C0C0 or #D0D0D0.
And don’t just trust the numbers. Perceived contrast matters too. Some color combinations technically pass WCAG minimums but are still a headache to read because of color fatigue or weird optical effects. This is where you need to get your designs in front of real users, especially people who use dark mode all the time or have mentioned visual sensitivities.
3. Adapt Imagery and Illustrations
Assets designed for a light background, your images, icons, and illustrations, will often look jarring and out of place in a dark theme. A bright, high-contrast photo with a white background can feel like a flashbang on a dark screen.
There are a few ways to handle these assets:
- Desaturation: Pull some of the saturation out of images for dark mode. This tones down their vibrancy so they don’t overpower the rest of the darker UI.
- Overlaying Tints: You can apply a semi-transparent dark overlay to images, which helps them recede into the background without making them unrecognizable.
- Separate Assets: For really important things like your logo or key illustrations, it’s often best to create a separate version specifically for dark mode. This could mean using lighter outlines, different fills, or getting rid of drop shadows that would just vanish on a dark surface.
- SVG Adjustments: If you’re using SVGs, you have a ton of flexibility. You can use CSS to target their fill and stroke colors and change them dynamically based on which theme is active.
If you’re working in a tool like Adobe XD, you can use component states for your icons and illustrations. This lets you set them up to automatically swap assets or apply different styles when the theme changes. Setting it up this way saves a huge amount of time compared to making manual tweaks everywhere.
| Aspect | Recommended Dark Mode Practice | Common Mistake / Avoid |
|---|---|---|
| Background Color | Dark grays (e.g., #121212, #1A1A1A) | Pure black (#000000) |
| Text Color | Off-white (e.g., #E0E0E0, #F0F0F0) | Pure white (#FFFFFF) |
| Normal Text Contrast Ratio | At least 4.5:1 (WCAG 2.1) | Below 4.5:1 |
| Large Text Contrast Ratio | At least 3:1 (WCAG 2.1) | Below 3:1 |
| Color System | Semantic color naming (e.g., primary-background) | Direct hex code mapping / Inversion |
| Image Adaptation | Desaturation, tints, separate assets | Using light mode images as-is |
“The update, which is rolling out to all users alongside GPT-6, gives ChatGPT the ability to combine a text response with diagrams, charts, forms, tappable buttons, and more.”
4. Handle Shadows and Elevation
In light mode, we use dark shadows to show elevation and create a sense of hierarchy. But that model breaks in dark mode, where a dark shadow on a dark background is completely invisible. So what do you do? You can either use lighter shadows and glows or, more commonly, just make the elevated surface itself a slightly lighter color.
A raised card in light mode, for example, might have a standard black shadow: box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2). In dark mode, that same card might not have a shadow at all. Instead, its background color could be a step lighter than the main app background, maybe with a subtle inner glow to show it’s floating. Google’s Material Design docs for dark theme actually recommend increasing the luminance of higher surfaces to create that separation.
Think about a mobile app’s bottom nav bar. In light mode, you’d give it a little shadow pointing up. For dark mode, you might make the bar a slightly lighter gray than the main content area and add a thin 1px light border on top to define its edge. The goal is to keep that feeling of depth and a clear hierarchy without ruining the whole dark look.
5. Implement Theme Switching Mechanisms
Users want control. You need to give them a clear, obvious way to switch between light and dark modes. The standard ways to do this are:
- System Preference Sync: Your app should automatically detect and follow the user’s system-wide dark mode setting on iOS or Android. This is the baseline expectation now.
- In-App Toggle: Even if you sync with the system, you *must* have a toggle somewhere in your app’s settings. Some people want your app in dark mode while the rest of their phone is light, or vice-versa.
- Time-Based Switching: A less common but nice touch is to automatically switch to dark mode at sunset and back to light at sunrise.
The toggle usually lives in a “Settings” or “Appearance” screen. When you build it, make sure the switch between modes is smooth and doesn’t create a jarring flash of white. Modern frameworks like React Native and Jetpack Compose have theme management built-in that can handle these transitions pretty gracefully.
Pro Tip: Test on Multiple Devices and OS Versions
How dark mode actually looks can change a lot between different phones and OS versions. An iPhone 15 Pro Max with an OLED display renders color completely differently than an older Android phone with an LCD screen, so you can’t just rely on simulators. You absolutely have to test your dark theme on a range of real hardware to find weird rendering bugs, color shifts, or performance hiccups. This is especially true for certain shades of blue or red, which can look way too lively on an OLED and cause eye fatigue if you haven’t toned them down.
Getting dark mode right is about more than just inverting colors. It’s a whole process that forces you to think carefully about color semantics, contrast, visual hierarchy, and giving users control. If you follow these guidelines, you can build a mobile UI that looks good and is also accessible and functional, which helps with everything from user trust and mobile UX security to the long-term mobile app evolution. Making sure your dark mode strategy works well with platform-specific tech like the Windows 11 AI mobile dev experience or the SwiftUI iOS UI revolution is also part of the job.
What’s the problem with using pure black (#000000) for a background?
Pure black creates way too much contrast with pure white text. This causes eye strain and a “blooming” effect on OLED screens, where the light from the text seems to bleed into the pure black background. Using dark grays like #121212 gives you enough contrast but is much easier on the eyes.
What is a semantic color system, and why do I need one for dark mode?
A semantic color system means naming colors based on their job (like background-primary or text-on-surface) instead of their hex code. This is the right way to do it because you can switch the entire app to dark mode just by changing what hex codes those names point to, which keeps everything consistent and easy to update.
How can I stop my images from looking terrible in dark mode?
You can desaturate them a bit, apply a dark tint to make them blend in, or for really important graphics, create a second version that’s designed for a dark background. If you’re using SVGs, you can just use CSS to change their fill and stroke colors when the theme switches.
What’s the minimum contrast ratio for text in dark mode?
You need to follow the WCAG 2.1 guidelines: hit a minimum contrast of 4.5:1 for normal text and 3:1 for large text (defined as 18pt or 14pt bold). This isn’t optional if you want your app to be readable.
Should my app just copy the system’s dark mode setting, or do I need a toggle?
Following the system preference is a great default, but you absolutely need to give users an in-app toggle too. People expect to have the final say on whether your specific app is light or dark, no matter what their OS is set to.