Best fit
- Use when building Home Screen, Lock Screen, StandBy, or CarPlay widgets with timeline providers; configurable widgets with AppIntentTimelineProvider; interactive widgets or Control Center controls with Button/Toggle wir…
dpearson2699/swift-ios-skills
Implement, review, or improve WidgetKit widgets and controls. Use when building Home Screen, Lock Screen, StandBy, or CarPlay widgets with timeline providers; configurable widgets with AppIntentTimelineProvider; interactive widgets or Control Center controls with Button/Toggle wiring; WidgetKit push reloads, refresh budgets, deep links, Smart Stack relevance, Liquid Glass/accented rendering, widget extension setup, WidgetBundle, App Groups, and entitlements.
npx skills add https://github.com/dpearson2699/swift-ios-skills --skill "skills/widgetkit"Source checked Jul 28, 2026·Refresh due Oct 26, 2026
Reorganized from the pinned upstream SKILL.md
Build home screen widgets, Lock Screen widgets, Control Center controls, and StandBy or CarPlay widget surfaces for iOS 26+.
npx skills add https://github.com/dpearson2699/swift-ios-skills --skill "skills/widgetkit"The pinned source contains enough sections and task detail for a source-grounded deep guide; automated content is still not an independent test.
1,891 source words · 27 usable sections
Best fit
Review workflow
Sections are extracted automatically from the pinned SKILL.md and link back to the source.
1. Add a Widget Extension target in Xcode (File New Target Widget Extension). 2. Enable App Groups for shared data between the app and widget extension. 3. Define a TimelineEntry struct with a date property and display data. 4. Implement a TimelineProvider (static) or AppIntentT…
Run through the Review Checklist at the end of this document.
[ ] Widget extension target has App Groups entitlement matching the main app
1. Add a Widget Extension target in Xcode (File New Target Widget Extension). 2. Enable App Groups for shared data between the app and widget extension. 3. Define a TimelineEntry struct with a date property and display data. 4. Implement a TimelineProvider (static) or AppIntentT…
1. Register an ActivityConfiguration in the widget bundle when the app has a Live Activity, but keep ActivityAttributes, request/update/end, APNs content-state, and Dynamic Island layout depth in activitykit. 2. Place Button, Toggle, ControlWidgetButton, and ControlWidgetToggle…
SkillSignal prompt templates
These prompts were written by SkillSignal from the source structure; they are not upstream text.
Source-grounded prompt
Use for a review or audit task while explicitly checking the source sections.
Use widgetkit for this review or audit task: [task]. Inputs and constraints: [details]. Work through these pinned SKILL.md sections: “Workflow”, “4. Review existing widget code”, “Review Checklist”, “1. Create a new widget”, “2. Integrate adjacent surfaces”. Cite the concrete requirements that shape each step, do not invent capabilities absent from the source, and verify the result against: [acceptance criteria].
Review checklist
The source section “Workflow” has been checked.
The source section “4. Review existing widget code” has been checked.
The source section “Review Checklist” has been checked.
The source section “1. Create a new widget” has been checked.
Choose a different workflow
Author, review, migrate, simulate, and troubleshoot official Opentrons Python Protocol API v2 protocols for Flex and OT-2 robots. Use for robot-specific liquid handling, deck and labware setup, pipettes, modules, runtime parameters, liquid classes, and Opentrons App analysis. Use pylabrobot instead when one workflow must support multiple robot vendors.
A separate implementation from K-Dense-AI/scientific-agent-skills; compare its source, maintenance signals, and permission requirements.
Open source detailDevelop and review PyLabRobot lab-automation resources, liquid-handling plans, offline simulations, and supported-device integrations. Use for PyLabRobot protocols or API questions; keep physical execution behind an explicit operator safety gate.
A separate implementation from K-Dense-AI/scientific-agent-skills; compare its source, maintenance signals, and permission requirements.
Open source detailBuilds and debugs Shopify themes (.liquid files, theme.json, sections), develops custom Shopify apps (shopify.app.toml, OAuth, webhooks), and implements Storefront API integrations for headless storefronts. Use when building or customizing Shopify themes, creating Hydrogen or custom React storefronts, developing Shopify apps, implementing checkout UI extensions or Shopify Functions, optimizing performance, or integrating third-party services. Invoke for Liquid templating, Storefront API, app dev
A separate implementation from Jeffallan/claude-skills; compare its source, maintenance signals, and permission requirements.
Open source detailFAQ
Build home screen widgets, Lock Screen widgets, Control Center controls, and StandBy or CarPlay widget surfaces for iOS 26+.
The source record exposes this install command: npx skills add https://github.com/dpearson2699/swift-ios-skills --skill "skills/widgetkit". Inspect the command and pinned source before running it.
Quality breakdown
Based on traceable docs and repository signals; stars are not treated as quality.
Compare before choosing
These links are selected from shared tasks, functions, stacks, platforms, and same-name variants. Compare the source owner, documentation, permissions, and maintenance signals.
Author, review, migrate, simulate, and troubleshoot official Opentrons Python Protocol API v2 protocols for Flex and OT-2 robots. Use for robot-specific liquid handling, deck and labware setup, pipettes, modules, runtime parameters, liquid classes, and Opentrons App analysis. Use pylabrobot instead when one workflow must support multiple robot vendors.
Develop and review PyLabRobot lab-automation resources, liquid-handling plans, offline simulations, and supported-device integrations. Use for PyLabRobot protocols or API questions; keep physical execution behind an explicit operator safety gate.
Builds and debugs Shopify themes (.liquid files, theme.json, sections), develops custom Shopify apps (shopify.app.toml, OAuth, webhooks), and implements Storefront API integrations for headless storefronts. Use when building or customizing Shopify themes, creating Hydrogen or custom React storefronts, developing Shopify apps, implementing checkout UI extensions or Shopify Functions, optimizing performance, or integrating third-party services. Invoke for Liquid templating, Storefront API, app dev
Implement, review, or improve SwiftUI Liquid Glass effects for iOS 26+. Covers glassEffect modifier, GlassEffectContainer, glass button styles, glass toolbar/tab bar, static status badges vs interactive controls, morphing transitions, tinting, interactive glass, ToolbarSpacer, scrollEdgeEffectStyle, backgroundExtensionEffect, and availability gating. Use when asked about Liquid Glass, glass buttons, glassEffect, GlassEffectTransition, glassEffectID, glassEffectUnion, scroll edge effects, or adop
Use when the user says "review the design", "check the UI", or wants a comprehensive UI/UX review. Uses a 7-phase methodology covering interaction, responsiveness, accessibility, and more.
Build home screen widgets, Lock Screen widgets, Control Center controls, and StandBy or CarPlay widget surfaces for iOS 26+.
Keep adjacent-framework guidance scoped to WidgetKit integration. Include
ActivityKit and App Intents only where they connect directly to WidgetKit
surfaces; hand off full lifecycle, APNs content-state, Siri/Shortcuts/Spotlight,
or entity-modeling work to sibling activitykit or app-intents skills.
See references/widgetkit-advanced.md for timeline strategies, push-based updates, Xcode setup, and advanced patterns.
TimelineEntry struct with a date property and display data.TimelineProvider (static) or AppIntentTimelineProvider (configurable).WidgetFamily.Widget conforming struct with a configuration and supported families.WidgetBundle annotated with @main.ActivityConfiguration in the widget bundle when the app has a
Live Activity, but keep ActivityAttributes, request/update/end, APNs
content-state, and Dynamic Island layout depth in activitykit.Button, Toggle, ControlWidgetButton, and ControlWidgetToggle
in WidgetKit views or controls, but keep intent modeling, entities, queries,
Siri, Shortcuts, and Spotlight in app-intents.AppIntent/OpenIntent for a button, or a SetValueIntent for a toggle.ControlWidgetButton or ControlWidgetToggle in the widget bundle.StaticControlConfiguration or AppIntentControlConfiguration.Run through the Review Checklist at the end of this document.
Every widget conforms to the Widget protocol and returns a WidgetConfiguration
from its body.
struct OrderStatusWidget: Widget {
let kind: String = "OrderStatusWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: OrderProvider()) { entry in
OrderWidgetView(entry: entry)
}
.configurationDisplayName("Order Status")
.description("Track your current order.")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
Use WidgetBundle to expose multiple widgets from a single extension.
@main
struct MyAppWidgets: WidgetBundle {
var body: some Widget {
OrderStatusWidget()
FavoritesWidget()
DeliveryActivityWidget() // ActivityConfiguration handoff
QuickActionControl() // Control Center
}
}
Use StaticConfiguration for non-configurable widgets. Use AppIntentConfiguration
(recommended) for configurable widgets paired with AppIntentTimelineProvider.
// Static
StaticConfiguration(kind: "MyWidget", provider: MyProvider()) { entry in
MyWidgetView(entry: entry)
}
// Configurable
AppIntentConfiguration(kind: "ConfigWidget", intent: SelectCategoryIntent.self,
provider: CategoryProvider()) { entry in
CategoryWidgetView(entry: entry)
}
| Modifier | Purpose |
|---|---|
.configurationDisplayName(_:) | Name shown in the widget gallery |
.description(_:) | Description shown in the widget gallery |
.supportedFamilies(_:) | Array of WidgetFamily values |
.supplementalActivityFamilies(_:) | Live Activity sizes (.small, .medium) |
For static (non-configurable) widgets. Uses completion handlers. Three required methods:
struct WeatherProvider: TimelineProvider {
typealias Entry = WeatherEntry
func placeholder(in context: Context) -> WeatherEntry {
WeatherEntry(date: .now, temperature: 72, condition: "Sunny")
}
func getSnapshot(in context: Context, completion: @escaping (WeatherEntry) -> Void) {
let entry = context.isPreview
? placeholder(in: context)
: WeatherEntry(date: .now, temperature: currentTemp, condition: currentCondition)
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<WeatherEntry>) -> Void) {
Task {
let weather = await WeatherService.shared.fetch()
let entry = WeatherEntry(date: .now, temperature: weather.temp, condition: weather.condition)
let nextUpdate = Calendar.current.date(byAdding: .hour, value: 1, to: .now)!
completion(Timeline(entries: [entry], policy: .after(nextUpdate)))
}
}
}
For configurable widgets. Uses async/await natively. Receives user intent configuration.
struct CategoryProvider: AppIntentTimelineProvider {
typealias Entry = CategoryEntry
typealias Intent = SelectCategoryIntent
func placeholder(in context: Context) -> CategoryEntry {
CategoryEntry(date: .now, categoryName: "Sample", items: [])
}
func snapshot(for config: SelectCategoryIntent, in context: Context) async -> CategoryEntry {
let items = await DataStore.shared.items(for: config.category)
return CategoryEntry(date: .now, categoryName: config.category.name, items: items)
}
func timeline(for config: SelectCategoryIntent, in context: Context) async -> Timeline<CategoryEntry> {
let items = await DataStore.shared.items(for: config.category)
let entry = CategoryEntry(date: .now, categoryName: config.category.name, items: items)
return Timeline(entries: [entry], policy: .atEnd)
}
}
| Family | Platform |
|---|---|
.systemSmall | iOS, iPadOS, macOS, CarPlay (iOS 26+) |
.systemMedium | iOS, iPadOS, macOS |
.systemLarge | iOS, iPadOS, macOS |
.systemExtraLarge | iPadOS only |
.accessoryCircular | iOS, watchOS |
.accessoryRectangular | iOS, watchOS |
.accessoryInline | iOS, watchOS |
.accessoryCorner | watchOS only |
Adapt layout per family using @Environment(\.widgetFamily):
@Environment(\.widgetFamily) var family
var body: some View {
switch family {
case .systemSmall: CompactView(entry: entry)
case .systemMedium: DetailedView(entry: entry)
case .accessoryCircular: CircularView(entry: entry)
default: FullView(entry: entry)
}
}
Use Button and Toggle with intent types available to the widget extension or
shared code. WidgetKit owns the view placement; app-intents owns intent
modeling and behavior.
struct InteractiveWidgetView: View {
let entry: FavoriteEntry
var body: some View {
Button(intent: ToggleFavoriteIntent(itemID: entry.itemID)) {
Image(systemName: entry.isFavorite ? "star.fill" : "star")
}
}
}
WidgetKit registers Live Activity surfaces in the widget extension. Keep this
section to registration and rendering handoff; use activitykit for
ActivityAttributes, lifecycle, push updates, and full Dynamic Island patterns.
struct DeliveryActivityWidget: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: DeliveryAttributes.self) { context in
DeliveryLiveActivityView(context: context)
} dynamicIsland: { context in
DeliveryDynamicIsland(context: context)
}
}
}
WidgetKit owns control configuration, placement, kind, display name, push
handler, and extension registration. Control actions and value intents belong in
app-intents.
struct OpenCameraControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "OpenCamera") {
ControlWidgetButton(action: OpenCameraIntent()) {
Label("Camera", systemImage: "camera.fill")
}
}
.displayName("Open Camera")
}
}
struct FlashlightControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "Flashlight", provider: FlashlightValueProvider()) { value in
ControlWidgetToggle(isOn: value, action: ToggleFlashlightIntent()) {
Label("Flashlight", systemImage: value ? "flashlight.on.fill" : "flashlight.off.fill")
}
}
.displayName("Flashlight")
}
}
Use accessory families and AccessoryWidgetBackground.
struct StepsWidget: Widget {
let kind = "StepsWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: StepsProvider()) { entry in
ZStack {
AccessoryWidgetBackground()
VStack {
Image(systemName: "figure.walk")
Text("\(entry.stepCount)").font(.headline)
}
}
}
.supportedFamilies([.accessoryCircular, .accessoryRectangular, .accessoryInline])
}
}
Small system widgets can appear in StandBy and CarPlay. Use
@Environment(\.widgetLocation) for conditional rendering:
@Environment(\.widgetLocation) var location
// location == .standBy, .homeScreen, .lockScreen, .carPlay, etc.
Use one .widgetURL(_:) as the whole-widget fallback route. Use Link for
deliberate subtargets only where the family and layout support them, including
.accessoryRectangular, .systemSmall, and larger system widgets. For small
widgets, prefer one clear fallback; avoid multiple Link targets unless the
visual affordance and hit areas remain unambiguous.
Never attach multiple widgetURL modifiers in the hierarchy.
Use TimelineEntryRelevance(score:duration:) on timeline entries for timely
iPhone and iPad Smart Stack relevance. Keep scores on a consistent positive
scale; zero or lower means not relevant.
For configurable widgets, donate App Intents that correspond to user actions or
widget parameters from app-side code, such as with intent.donate() or
IntentDonationManager. Keep AppEntity and EntityQuery design in
app-intents.
On watchOS, contextual relevance uses
WidgetRelevance([WidgetRelevanceAttribute(...)]) from the provider
relevance() callback. That path is not used by iPhone or iPad Smart Stacks.
Gauge over manual arcs. Use .gaugeStyle(.accessoryCircular) for
Lock Screen circular widgets and .linearCapacity for home screen capacity bars.
The system handles styling, accessibility, and rendering-mode adaptation..containerBackground(_:for: .widget) (iOS 17+) for widget backgrounds
instead of padding and background modifiers.Canvas for dense visualizations like sparklines or mini bar charts.
The lack of per-element accessibility is acceptable since the entire widget
surface is a single tap target.Text(timerInterval:countsDown:) for live countdowns. Load the advanced reference for current budget guidance.See references/widgetkit-advanced.md for code examples and detailed guidance on each pattern.
Adapt widgets to Liquid Glass with @Environment(\.widgetRenderingMode),
.widgetAccentable(), and Image.widgetAccentedRenderingMode(_:). In
.vibrant, the system maps content into the material style, so avoid relying on
original colors alone.
Widget push reloads:
WidgetPushHandler type in the widget extension target or shared
code linked into it, not only in the main app target..pushHandler(...) on the widget configuration.pushTokenDidChange(_:widgets:).apns-push-type: widgets, topic suffix .push-type.widgets, and
aps.content-changed.WidgetCenter reloads remain the fallback path.Control push reloads:
ControlPushHandler with .pushHandler(...) on the
ControlWidgetConfiguration.pushTokensDidChange(controls:) receives [ControlInfo]; read tokens from
each control's pushInfo.apns-push-type: controls, topic suffix .push-type.controls, and
aps.content-changed.Small system widgets can appear in CarPlay on iOS 26+. Ensure layouts are legible at a glance; taps and controls depend on vehicle touch support and, for opening the app, CarPlay integration.
Using IntentTimelineProvider instead of AppIntentTimelineProvider.
IntentTimelineProvider is the older SiriKit Intents-based provider. Prefer
AppIntentTimelineProvider with the App Intents framework for new widgets.
Exceeding the refresh budget. Widgets have a daily refresh limit. Do not
call WidgetCenter.shared.reloadTimelines(ofKind:) on every minor data change.
Batch updates and use appropriate TimelineReloadPolicy values.
Forgetting App Groups for shared data. The widget extension runs in a
separate process. Use UserDefaults(suiteName:) or a shared App Group
container for data the widget reads.
Performing network calls in placeholder(). placeholder(in:) must return
synchronously with sample data. Use getTimeline or timeline(for:in:) for
async work.
Treating WidgetKit push payloads as state. Widget and control pushes are reload signals. Persist state in shared storage or refetch it in the provider.
Registering widget pushes through User Notifications. Widget push tokens
come from WidgetKit handlers, not UNUserNotificationCenter.
Putting heavy logic in the widget view. Widget views are rendered in a size-limited process. Pre-compute data in the timeline provider and pass display-ready values through the entry.
Ignoring accessory rendering modes. Lock Screen widgets render in
.vibrant or .accented mode, not .fullColor. Test with
@Environment(\.widgetRenderingMode) and avoid relying on color alone.
Not testing on device. StandBy, CarPlay, and accessory rendering differ significantly from Simulator. Always verify on physical hardware.
@main is on the WidgetBundle, not on individual widgetsplaceholder(in:) returns synchronously; getSnapshot/snapshot(for:in:) fast when isPreviewreloadTimelines(ofKind:) only on data changeWidgetFamily; accessory widgets tested in .vibrant modeButton/Toggle only.widgetURL(_:) fallback is used; Link subtargets are family-appropriateStaticControlConfiguration/AppIntentControlConfiguration