Dark Mode is no longer optional — users expect it. Here's how to implement it properly in SwiftUI.
The Basics: Color Scheme
SwiftUI provides @Environment(\.colorScheme) to detect the current mode:
struct ContentView: View {
@Environment(\.colorScheme) var colorScheme
var body: some View {
Text("Hello")
.foregroundColor(colorScheme == .dark ? .white : .black)
}
}
But there's a better way...
Use Semantic Colors
SwiftUI has built-in colors that adapt automatically:
Text("Adapts automatically")
.foregroundColor(.primary) // Black in light, white in dark
.background(Color(.systemBackground)) // White in light, black in dark
Key semantic colors:
-
.primary/.secondary— text colors -
Color(.systemBackground)— main background -
Color(.secondarySystemBackground)— grouped content
Create a Theme System
For full control, create a theme:
struct AppTheme {
let background: Color
let text: Color
let accent: Color
static let light = AppTheme(
background: .white,
text: .black,
accent: .blue
)
static let dark = AppTheme(
background: Color(.systemGray6),
text: .white,
accent: .cyan
)
}
Use it with environment:
struct ThemeKey: EnvironmentKey {
static let defaultValue = AppTheme.light
}
extension EnvironmentValues {
var theme: AppTheme {
get { self[ThemeKey.self] }
set { self[ThemeKey.self] = newValue }
}
}
Preview Both Modes
Always test both modes in previews:
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView()
.preferredColorScheme(.light)
ContentView()
.preferredColorScheme(.dark)
}
}
}
Common Mistakes
- Hardcoding colors — Use semantic colors instead
- Forgetting images — Use SF Symbols or provide dark variants
- Not testing — Always preview both modes
Skip the Setup
If you want Dark Mode already configured with a complete theme system, check out SwiftUI Starter Kit Pro. It includes a production-ready theme with automatic dark mode support.
Questions? Drop them below!
Follow @SwiftUIDaily for daily SwiftUI tips.
Top comments (0)