How it works
A widget is the configuration for a glanceable piece of your app's content that the system displays on the Home Screen, in the Today View, on the Lock Screen, or in other widget surfaces. You conform a type to Widget to declare that configuration — its kind, its supported families, and the SwiftUI view that draws each entry of timeline data. Reach for Widget when you want to surface timely, at-a-glance information outside your app, without the user opening it. The protocol is the entry point that ties a widget's identity, its configuration, and its view together into something the system can install and refresh.
Conform a type to Widget and provide a configuration
A
Widgetis a value type whose single requirement is abodyof typesome WidgetConfiguration. The system asks for that configuration to learn the widget's identity and how to build its content. The view shown for each timeline entry is an ordinary SwiftUI view hierarchy — the same kind you see in the accompanyingWidgetDemo, where aVStackofTextandImagelays out an "Up Next" card.Choose a configuration kind
Inside
bodyyou return either aStaticConfiguration, for widgets with no user-set parameters, or anAppIntentConfiguration, for widgets the user can customize by editing. The configuration is initialized with akindstring that uniquely identifies the widget within your app, plus aproviderthat supplies timeline entries and a closure that renders each entry into a view like the card built inWidgetDemo.Drive content from a TimelineProvider
The configuration's provider conforms to
TimelineProvider(orAppIntentTimelineProvider) and produces dated entries that tell the system what to show and when to refresh. Each entry is handed to your view-building closure, so values such as theText("Team Standup")event title and theText("10:00 AM")time would come from the current entry rather than being hard-coded as they are in the demo.Declare supported families and metadata with modifiers
Apply modifiers to the returned configuration to describe where and how the widget appears:
supportedFamilies(_:)lists sizes like.systemSmallor.systemMedium, whileconfigurationDisplayName(_:)anddescription(_:)provide the title and subtitle shown in the widget gallery. The fixed.frame(width: 160, height: 160)inWidgetDemostands in for the system-sized frame a real widget family would impose.Register the widget in a WidgetBundle
A
Widgettype does not run on its own — you expose it through a@maintype conforming toWidgetBundle, listing eachWidgetin the bundle'sbody. This is how the system discovers your widgets and offers them for the user to add to a widget surface, where the card laid out inWidgetDemowould finally be drawn.
Text("10:00 AM") in WidgetDemo to read from a timeline entry's date so the widget shows a value that updates as the system refreshes it, demonstrating how Widget content is driven by its provider rather than fixed in the view.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct WidgetDemo: View {
var body: some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
Image(systemName: "calendar")
.foregroundStyle(.red)
Text("Up Next")
.font(.caption)
.foregroundStyle(.secondary)
Spacer()
}
Text("Team Standup")
.font(.headline)
Text("10:00 AM")
.font(.title2.bold())
.foregroundStyle(.blue)
}
.padding()
.frame(width: 160, height: 160)
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: 20))
.padding()
}
}