Dark Mode vs Light Mode: One Theme, Both Done Right
You do not design two apps, you design one set of meanings: name your colors by role, and light and dark fall out for free.
TL;DR
Supporting light and dark mode well means using semantic, role-based colors (background, label, accent) that adapt automatically, not two separately hardcoded palettes. Build a themeable app from a free VP0 design with a token-based color system, test real screens in both modes, check contrast in each, and respect the system setting. Mind images, shadows, and elevation, which behave differently in dark mode. One coherent theme, two clean appearances.
Supporting dark and light mode is not designing two apps; it is designing one system of meanings that renders correctly in both. The short answer: use semantic, role-based colors (background, secondary background, label, accent) that adapt automatically, build the app from a free VP0 design with a token-based color system, and test real screens in both modes. Most people use dark mode at least some of the time, around 82% of users in one Android Authority survey, so both appearances have to look right.
Think in roles, not hex codes
The mistake that makes theming painful is hard-coding hex values everywhere, then trying to maintain a second hard-coded set for dark mode. Instead, name colors by their role, label, secondary label, background, grouped background, separator, accent, and define what each role resolves to in light and in dark. Then your UI references roles, and switching modes is automatic and consistent. iOS provides semantic system colors that already do this; for custom colors, define both appearances. This is the same idea as design tokens: meaning first, value second. Apple’s Human Interface Guidelines on color and dark mode explain the semantic approach.
Build it from a free design
VP0 is a free iOS design library for AI builders. Pick the screens you need, copy their links, and have Cursor or Claude Code rebuild them in SwiftUI using semantic colors and asset-catalog color sets that define light and dark variants, rather than literal hex codes scattered through the code. Respect the system appearance by default (do not force one mode), and if you offer an in-app toggle, persist it. Then test real screens in both: check contrast in each mode (dark mode is not just inverted, it has its own contrast needs), and handle images, shadows, and elevation, which often need dark-specific treatment. For the foundational guide, see light and dark mode design for iOS apps, and for overall polish, see how to make my app look better.
Light and dark, role by role
Define each role for both appearances.
| Color role | Light | Dark |
|---|---|---|
| Background | Near-white | Near-black, not pure |
| Label | Near-black | Near-white |
| Secondary | Muted gray | Lighter muted gray |
| Accent | Brand color | Adjusted for contrast |
| Elevation | Shadows | Lighter surfaces |
Common mistakes
The first mistake is hard-coded hex colors that ignore the appearance, so dark mode looks broken. The second is treating dark mode as a simple inversion, when contrast and elevation need their own thought. The third is pure black backgrounds and pure white text, often too harsh; soften slightly. The fourth is images and icons that only work on one background. The fifth is forcing a single mode instead of respecting the system setting. Think in roles, define both, and test both.
A worked example
Say you theme an app. From a VP0 design, you define semantic color sets in the asset catalog, background, label, secondary, accent, each with a light and a dark value, and your UI references those roles, never raw hex. In light mode it is near-white with dark text; in dark mode, near-black (not pure) with near-white text and a slightly adjusted accent for contrast. Shadows become subtle lighter surfaces in dark mode, and images have dark-appropriate variants. You test every screen in both and check contrast. One theme, two clean looks. For the sensory-friendly angle, see low stimulation UI kit for autism, and for a DIY smart-home dashboard next, see Home Assistant dashboard mobile UI clone.
Key takeaways
- Supporting both modes means one role-based color system, not two hardcoded palettes.
- Build a themeable app from a free VP0 design using semantic colors and color sets.
- Name colors by role and define light and dark values for each.
- Test real screens in both modes and check contrast in each.
- Mind images, shadows, and elevation, which need dark-specific treatment.
Frequently asked questions
How do I support dark and light mode properly? Use semantic, role-based colors (background, label, accent) defined for both appearances, build from a free VP0 design, respect the system setting, and test real screens in both modes.
Is dark mode just inverting the colors? No. Dark mode has its own contrast and elevation needs. Use near-black (not pure black) backgrounds, adjust accents for contrast, and handle shadows and images for the dark appearance specifically.
Why use semantic colors instead of hex codes? Because role-based colors adapt automatically across light and dark and stay consistent, while scattered hex codes force you to maintain two palettes and often break in one mode.
Should I add an in-app dark mode toggle? Respect the system setting by default. You can offer an optional in-app toggle, but if you do, persist the user’s choice so it sticks across launches.
Frequently asked questions
How do I support dark and light mode properly?
Use semantic, role-based colors (background, label, accent) defined for both appearances, build from a free VP0 design, respect the system setting, and test real screens in both modes.
Is dark mode just inverting the colors?
No. Dark mode has its own contrast and elevation needs. Use near-black (not pure black) backgrounds, adjust accents for contrast, and handle shadows and images for the dark appearance specifically.
Why use semantic colors instead of hex codes?
Because role-based colors adapt automatically across light and dark and stay consistent, while scattered hex codes force you to maintain two palettes and often break in one mode.
Should I add an in-app dark mode toggle?
Respect the system setting by default. You can offer an optional in-app toggle, but if you do, persist the user's choice so it sticks across launches.
Part of the Native Apple & SwiftUI: The iOS Ecosystem hub. Browse all VP0 topics →
Keep reading
Light and Dark Mode Design for iOS Apps
Dark mode is a default expectation, not a coat of paint. Here is how to design iOS apps for both modes with semantic colors so it is nearly free, not a retrofit.
How to Design an iOS App Before You Build It With AI
AI builders match references, not vague goals. Deciding your core screen, flow, data, and feel first is the cheapest hour in the whole project.
Airbnb-Style Bottom Sheet in React Native: Map Meets List
Airbnb's map-plus-draggable-sheet is a gold-standard pattern. Build a smooth bottom sheet over a map from a free VP0 design in React Native, with the right detents.
Sign in with Apple UI Guidelines, Built in Figma
Sign in with Apple has strict button and flow rules. Build a compliant sign-in from a free VP0 design, follow guideline 4.8, and cut account-creation friction.
Barcode Scanner Viewfinder UI for Mobile Apps
A barcode scanner viewfinder needs a dark overlay, a clear cutout, and instant feedback. Build one from a free VP0 design and power it with Apple VisionKit.
Bento Box UI: The Grid Layout, Used With Purpose
Bento grids look great but need real hierarchy. Build a bento-box layout from a free VP0 design where each tile earns its size, stays accessible, and reads in order.