Hierarchical background styles in SwiftUI

Before iOS 17 to get hierarchical system background colors in SwiftUI we usually had to convert them from UIColor. For example, to get the secondary system background we would write the following code: Color(uiColor: .secondarySystemBackground).

Starting from iOS 17 we now have new properties, such as secondary, tertiary, quaternary and quinary that are defined on an instance of a ShapeStyle. To get hierarchical background colors we simply have to access these properties on the current background style: BackgroundStyle().secondary. BackgroundStyle in SwiftUI conforms to ShapeStyle protocol, so accessing the secondary property on an instance of a BackgroundStyle will return the second level of the background in the current context that depends on the operating system and color scheme (light or dark mode enabled).

We can also get the current background style from the static background property defined on ShapeStyle.

We can see that if we put both the old and the new ways to get hierarchical system background colors side by side, they will be the same. UIKit system background colors go up to the tertiary one.

HStack {
    Image(systemName: "cat")
        .padding()
        .background(Color(uiColor: .secondarySystemBackground))
    
    Image(systemName: "cat")
        .padding()
        .background(.background.secondary)
}

...

Screenshot showing an image of a cat with secondary system background Screenshot showing an image of a cat with secondary system background

Unfortunately, the new instance properties are only available on iOS 17, so if you are supporting older OS versions, you would need to wrap their use in if #available(iOS 17.0, *) and fallback to the previous method for older targets.

if #available(iOS 17.0, *) {
    Image(systemName: "cat")
        .padding()
        .background(.background.secondary)
} else {
    Image(systemName: "cat")
        .padding()
        .background(Color(uiColor: .secondarySystemBackground))
}

Note, that the new instance properties for getting hierarchical shape styles that return some ShapeStyle are different from the static properties available on older iOS versions, such as primary, secondary, tertiary, quaternary and quinary that return HierarchicalShapeStyle. The new instance properties provide a hierarchical level of the shape style that they are accessed on, for example a hierarchical level of the current background style. The static properties always provide a hierarchical level of the current foreground style.

The new instance properties can be accessed on other shape styles too, not just the background style. For example, we can get hierarchical levels of a TintShapeStyle or any SwiftUI Color.

Image(systemName: "cat")
    .padding()
    .background(.tint.secondary)

...


Image(systemName: "cat")
    .padding()
    .background(.green.tertiary)
Screenshot showing levels of the blue tint color and green color Screenshot showing levels of the blue tint color and green color
Integrating SwiftUI into UIKit Apps by Natalia Panferova book coverIntegrating SwiftUI into UIKit Apps by Natalia Panferova book cover

Check out our book!

Integrating SwiftUI into UIKit Apps

Integrating SwiftUI intoUIKit Apps

UPDATED FOR iOS 17!

A detailed guide on gradually adopting SwiftUI in UIKit projects.

  • Discover various ways to add SwiftUI views to existing UIKit projects
  • Use Xcode previews when designing and building UI
  • Update your UIKit apps with new features such as Swift Charts and Lock Screen widgets
  • Migrate larger parts of your apps to SwiftUI while reusing views and controllers built in UIKit