Logo for tanaschita.com

How to support dark mode in SwiftUI programmatically

Learn how to improve type safety when working with semantic colors.

updated on 18 Mar 2024 · 4 min read

To add support for dark mode in an iOS application, Apple provides so called semantic colors which means they can have multiple values.

In this article, we'll look at how to define and use those semantic colors in code without using the asset catalog.

Let's directly jump in.

Sponsorship logo
Preparing for a technical iOS job interview - updated for iOS 18
Check out my book on preparing for a technical iOS job interview with over 200 questions & answers. Test your knowledge on iOS topics such as Swift, SwiftUI, Combine, HTTP Networking, Authentication, SwiftData & Core Data, Concurrency with async/await, Security, Automated Testing, Machine Learning and more.
LEARN MORE

At first, let's take a short look at how to define semantic colors via an asset catalog. Xcode provides a convenient way to do so:

Defining semantic colors via asset catalog.
Defining semantic colors via asset catalog.

To use that color in code, we call:

Color("primary")

When working with raw strings as shown in the example above, we loose type safety. To improve that, we could either

  • combine asset catalog with encapsulation

or

  • define these colors programmatically

The first option could look as follows:

extension Color {
static let primary = Color("primary")
static let secondary = Color("secondary")
}
Text("Some text")
.foregroundColor(.primary)

Another way is to not to use asset catalogs entirely but to define colors programmatically instead.

Defining colors programmatically

For the programmatic approach, we can use the userInterfaceStyle property of UITraitCollection to find out which color to use:

extension UIColor {
static func dynamicColor(light: UIColor, dark: UIColor) -> UIColor {
return UIColor { $0.userInterfaceStyle == .dark ? dark : light }
}
}

With the extension in place, we can use it as follows:

struct Colors {
var primary: Color {
return color(light: UIColor(red: 0.7, green: 1, blue: 0.7, alpha: 1),
dark: UIColor(red: 0.5, green: 1, blue: 0.5, alpha: 1))
private func color(light: UIColor, dark: UIColor) -> Color {
return Color(UIColor.dynamicColor(light: light, dark: dark))
}
}

Alternatively, we can use the same approach in a color extension.

Only supporting light mode

A quick tip at the end: as long as you are not supporting dark mode, set Info.plist key UIUserInterfaceStyle to Light.

This way, you can avoid unwanted appearance effects when users use your app with dark mode turned on.

Light Mode Only
Sponsorship logo
Preparing for a technical iOS job interview - updated for iOS 18
Check out my book on preparing for a technical iOS job interview with over 200 questions & answers. Test your knowledge on iOS topics such as Swift, SwiftUI, Combine, HTTP Networking, Authentication, SwiftData & Core Data, Concurrency with async/await, Security, Automated Testing, Machine Learning and more.
LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

ux

swift

ios

How to use TipKit to create tool tips in SwiftUI

Learn how to show feature hints as a popover to the user by using TipKit.

04 Mar 2024 · 5 min read

Latest articles and tips

© 2024 tanaschita.com

Privacy policy

Impressum