How to Detect Dark Mode in SwiftUI
Learn how to detect and respond to dark mode in SwiftUI using the color scheme environment value.
Overview
Detecting dark mode in SwiftUI allows you to customize your app's appearance or behavior based on the user's interface style. This is particularly useful for adjusting colors, images, or layout elements to match the system appearance. SwiftUI provides a simple and elegant way to observe the current color scheme using the @Environment property wrapper.
The Approach
You can use the @Environment property wrapper to observe the colorScheme environment value. This value updates automatically when the user switches between light and dark mode.
import SwiftUI
t struct ContentView: View {
@Environment(.colorScheme) var colorScheme
var body: some View {
VStack {
if colorScheme == .dark {
Text("Dark mode is active")
.foregroundColor(.white)
} else {
Text("Light mode is active")
.foregroundColor(.black)
}
}
.padding()
}
}
Step-by-Step Breakdown
- Import SwiftUI – Standard for any SwiftUI view.
- Define the
ContentViewstruct – A standard SwiftUI view. - Use
@Environment(.colorScheme)– This fetches the current color scheme from the environment. It updates automatically when the system appearance changes. - Conditional rendering – Based on the value of
colorScheme, we show different text and colors. - Apply padding – For better visual spacing.
This approach ensures that the UI updates in real-time when the user changes the appearance settings in the system.
Common Variations
Using a Binding for Dynamic Updates
Sometimes, you may want to bind the color scheme so that changes propagate through your app more dynamically.
struct ContentView: View {
@Environment(.colorScheme) var colorScheme
var body: some View {
Text(colorScheme == .dark ? "🌙 Dark" : "☀️ Light")
.animation(.default, value: colorScheme)
}
}
Custom View Modifier Based on Color Scheme
You can create a custom view modifier that applies different styles based on the current color scheme.
struct ConditionalModifier: ViewModifier {
func body(content: Content) -> some View {
content
.foregroundColor(ColorSchemeBinding().colorScheme == .dark ? .white : .black)
}
}
extension View {
func conditionalStyle() -> some View {
modifier(ConditionalModifier())
}
}
These variations help encapsulate logic and reuse it across multiple views.
Pitfalls to Avoid
- Assuming the color scheme is static – Avoid hardcoding assumptions about the color scheme. Always observe the environment value to ensure your UI reflects the latest system setting.
- Overusing animations – Animating color scheme changes can be jarring if not done subtly. Only animate when it enhances the user experience.
- Not testing both modes – Make sure to test your UI in both light and dark modes to catch layout or color contrast issues.
Related Guides
- how-to-detect-interface-style
- how-to-change-app-appearance
- how-to-create-dark-mode-toggle