WWDC24 deal: 30% off our Swift and SwiftUI books! Learn more ...WWDC24 deal:30% off our Swift and SwiftUI books >>

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
Books by Natalia PanferovaBooks by Natalia Panferova
WWDC24: 30% off all books!
  • Swift Gems

    100+ tips to take your Swift code to the next level

  • Integrating SwiftUI into UIKit Apps

    A detailed guide on gradually adopting SwiftUI in UIKit projects

The offer is active until the 16th of June.