How do widgets adapt to the tinted Home Screen and the Lock Screen: rendering modes, accented content and container backgrounds?

19.8.4 · L5 · Interview

Predict first

What are the three rendering modes and how is .never stored?

import WidgetKit
struct Entry: TimelineEntry { let date = Date.distantPast }
print(WidgetRenderingMode.fullColor, WidgetRenderingMode.accented, WidgetRenderingMode.vibrant)
print("never:", Timeline<Entry>(entries: [], policy: .never).policy)
print("atEnd:", Timeline<Entry>(entries: [], policy: .atEnd).policy)
  • fullColor accented vibrant; never is a date in the year 4001; atEnd has no date
  • light dark tinted; never has no date
  • fullColor accented vibrant; both policies have no date

Mental model. It is like printing a leaflet that must also work as a black-and-white photocopy: colour can help, but the message cannot depend on it.

A widget is not always drawn in full colour. @Environment(\.widgetRenderingMode) has three values (printed by the check): fullColor (normal Home Screen), accented (the user’s tint or Lock Screen accent: the system splits the view into an accent group and a primary group, and desaturates images) and vibrant (Lock Screen and StandBy, monochrome with vibrancy). You mark which views take the accent colour with .widgetAccentable(), give images .widgetAccentedRenderingMode(...), and put the background in .containerBackground(for: .widget) { … } (required from iOS 17) so the system can remove or replace it, for example in StandBy or on the tinted Home Screen. Content margins are also system-controlled; use .contentMarginsDisabled() only when you really need edge-to-edge.

Design for the lowest mode first: information must not depend on colour alone, because in accented and vibrant modes red and green both become shades of one tint. Test each mode in Xcode’s widget previews with the rendering-mode override, plus the Lock Screen families (accessoryCircular, accessoryRectangular, accessoryInline). The policy values printed in the same check show that .never is just a far-future reload date. Not run: the visual result, which needs a simulator UI or device.

Rendering modes are three values; the .never policy carries a far-future date.

Common traps

  • Drawing the background as a normal view. The system cannot remove it; use containerBackground(for: .widget).
  • Encoding status only by colour. It disappears in vibrant mode.

They might follow up with

  • How do I show different content per mode? Read the environment value and branch, but keep the layout stable.

Related questions

  • 19.4.1 How does a WidgetKit widget work: providers, timeline entries, reload policies, families and the refresh…
  • 19.6.3 How have watch complications moved from ClockKit to WidgetKit, and what are accessory families and the Smart…

← How do several widgets live in one extension, and what is a widget’s…