Skip to content
DeveloperMemos

Widget Troubles: Fixing Backgrounds and Padding in iOS 17

iOS, Widgets, iOS 17, SwiftUI, StandBy Mode1 min read

The arrival of iOS 17 last year brought exciting new features, but also a few hurdles for developers working with widgets. Let's tackle two common issues: missing backgrounds and unwanted padding.

The Vanishing Background

When you update your widget for iOS 17, you might find its background has mysteriously disappeared. This is because Standby mode removes elements deemed non-essential. To combat this, Apple introduced the containerBackground modifier. Here's how to use it, along with a handy backport extension for pre-iOS 17 versions:

1struct MyWidget: Widget {
2
3 var body: some WidgetConfiguration {
4 StaticConfiguration(kind: "MyWidget") {
5 // ... your widget content here
6
7 .widgetBackground(backgroundView: Color.white) // Set your desired background color
8 }
9 }
10}
11
12// Backport Extension (Optional): For compatibility with older iOS versions
13extension View {
14 func widgetBackground(backgroundView: some View) -> some View {
15 if #available(iOSApplicationExtension 17.0, *) {
16 return containerBackground(for: .widget) {
17 backgroundView
18 }
19 } else {
20 return background(backgroundView)
21 }
22 }
23}

The containerBackground modifier takes two arguments: a context and a closure that defines the background for that context. Here, we're setting the background for the standard widget context using a Color view. You can define backgrounds for other contexts as needed.

This code snippet also includes a backport extension named widgetBackground. This extension checks the iOS version and applies either containerBackground for iOS 17 or background for older versions, ensuring your widget displays a background consistently.

Padding Problems: Keeping Your Widget Compact

Another quirk of StandBy mode is the addition of extra padding around your widget. This can throw off your widget's layout. To address this, Apple offers the contentMarginsDisabled modifier. Here's how to use it, again with a backport extension:

1struct MyWidget: Widget {
2
3 var body: some WidgetConfiguration {
4 StaticConfiguration(kind: "MyWidget") {
5 // ... your widget content here
6
7 .contentMarginsDisabledIfAvailable() // Disable system-added margins
8 }
9 }
10}
11
12// Backport Extension (Optional): For compatibility with older iOS versions
13extension WidgetConfiguration {
14 func contentMarginsDisabledIfAvailable() -> some WidgetConfiguration {
15 if #available(iOSApplicationExtension 17.0, *) {
16 return self.contentMarginsDisabled()
17 } else {
18 return self
19 }
20 }
21}

The contentMarginsDisabled modifier simply tells the system not to add its own padding.

Important Note: The backport extension for contentMarginsDisabled is not strictly necessary if your widget only supports iOS 15 and above. While the modifier exists in iOS 15 and 16, it doesn't have any effect on those versions.