Home How to Create your Custom EnvironmentValues in SwiftUI
Post
Cancel

How to Create your Custom EnvironmentValues in SwiftUI

TLDR

A set of properties that easily exposes app-wide configuration to our views. A good example is \.colorScheme that tell us if the device is currently in light or dark mode.

Hey folks! If you’re here, I’m going to guess that you’re an iOS developer or enthusiast, and you’re working with SwiftUI. Today, we’re going to learn how to define and use our own custom environment values.

What’s the Deal with Environment Values?

It’s essentially a singleton that exposes app-wide configuration to our views in a friendly way.

They are set of predefined properties, that allows us to access current aspects of the app’s behavior and appearance. For example the device’s current color scheme (dark or light), the device’s current locale, the device’s current calendar, and size class (basically screen sizes).

SwiftUI provides a bunch of these out of the box. Properties like \.colorScheme, \.locale, \.horizontalSizeClass, \.calendar, \dynamicTypeSize and \.managedObjectContext are all familiar environment values.

But what if we want to add our own properties to this mix? Well, you’re in luck! SwiftUI lets us define and use custom environment values. And believe me, it’s as cool as it sounds. Here’s how it’s done.

Defining Custom Environment Values

Let’s say we’re building a hot new social media app, “ChatterBox”. We want to have a feature that lets users switch between light and dark themes, but we also want to include a “neon” theme because, why not, it’s 2023! SwiftUI’s built-in \.colorScheme environment value won’t cut it. So, let’s create our custom environment value.

First, we need to extend the EnvironmentValues struct with a computed property to include our new theme value:

1
2
3
4
5
6
7
8
9
10
enum Theme {
    case light, dark, neon
}

extension EnvironmentValues {
    var theme: Theme {
        get { self[ThemeKey.self] }
        set { self[ThemeKey.self] = newValue }
    }
}

In this snippet, Theme would be an enumeration of the different themes (light, dark, neon). ThemeKey is a key that we’ll define next.

We need to define a ThemeKey that conforms to the EnvironmentKey protocol as follows:

1
2
3
struct ThemeKey: EnvironmentKey {
    static let defaultValue: Theme = .light
}

With this setup, defaultValue is what’s used when no other value has been provided. Now let’s inject it into our views.

Injecting and Using Custom Environment Values

Now that we have our custom theme environment value, how do we use it? Well, it’s as easy as pie 🥧.

We can inject the current theme into our parent view like this:

1
2
3
4
NavigationStack {
    // Our awesome UI here
}
.environment(\.theme, .neon)

And voila! We’ve just injected the 'neon' theme into the environment. Any view inside the NavigationStack can now access it.

To read from the newly inject value in our environment, we’d do something like this:

1
2
3
4
5
6
@Environment(\.theme) var theme

var body: some View {
    Text("Welcome to ChatterBox!")
        .foregroundColor(theme == .neon ? .purple : .primary)
}

And just like that the text color will now respond dynamically to the current theme, be it light, dark or neon.

Conclusion

As we just explored using custom environment values in SwiftUI is powerful. They make our UIs super flexible and responsive to changes in globally-defined values. Plus, they’re a blast to work with once you get the hang of it.

This post is licensed under CC BY 4.0 by the author.