skills/generators/widget-generator/SKILL.md
Generate WidgetKit widgets for iOS/macOS home screen and lock screen with timeline providers, interactive elements, and App Intent configuration. Use when adding widgets to an app.
npx skillsauth add rshankras/claude-code-apple-skills widget-generatorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate a complete WidgetKit widget implementation with timeline providers, size-specific views, lock screen accessory widgets, interactive elements (iOS 17+), and App Intent configuration.
Use this skill when the user:
WidgetBundleSearch for existing widget code:
Glob: **/*Widget*.swift, **/*TimelineProvider*.swift
Grep: "WidgetKit" or "TimelineProvider" or "WidgetBundle" or "WidgetConfiguration"
If an existing widget extension is found:
WidgetBundle to extendIf a WidgetBundle already exists:
@main entry pointIf widget code with the same name exists:
Widgets require:
Ask user via AskUserQuestion:
What is this widget for? (freeform)
Which widget sizes should be supported?
What type of widget?
StaticConfiguration) -- content updated on a schedule, no user configurationAppIntentConfiguration, iOS 17+) -- user can choose what the widget displays via long-press editAppIntentConfiguration + Button/Toggle, iOS 17+) -- user can tap buttons or toggles directly on the widgetWhat is the data source?
How often should the widget update?
WidgetCenter.shared.reloadTimelines(ofKind:)Check project structure:
For widget extension files:
MyAppWidgets/)For shared data models (if using App Groups):
Sources/ or Shared/ exists --> place thereGenerate these files based on configuration answers:
{Name}Widget.swift -- Widget definition with configuration
Widget struct with StaticConfiguration or AppIntentConfiguration{Name}TimelineProvider.swift -- Timeline logic
TimelineProvider (static) or AppIntentTimelineProvider (configurable){Name}Entry.swift -- Timeline entry model
TimelineEntry struct with date and display data{Name}WidgetViews.swift -- Size-specific views
containerBackground for iOS 17+ removable backgrounds{Name}AppIntent.swift (if interactive or configurable)
WidgetConfigurationIntent for configurable widgetsAppIntent for interactive widget buttons/togglesUse the templates in templates.md and customize based on user answers:
Apply these when generating the size-specific views. A good widget idea is at least one of personal (the user's own data), informational (the most-wanted status at a glance), or contextual (the right thing for this moment). Glanceability is the bar — a widget is read in about a second on the way somewhere else.
| Rule | Specific | |------|----------| | Small widget | Max ~4 pieces of information; exactly one tap target (the whole widget) | | Medium/Large | Multiple tap targets allowed — cell style for visually contained targets, content style for uncontained lists | | Margins | 16pt default; 11pt acceptable for tighter graphical shapes (circles, glyphs) | | Corners | Inner shapes must be concentric with the widget's corner radius | | Layouts | Design each family separately — never scale the small layout up to medium/large | | Typography | SF Pro, SF Pro Rounded, or SF Mono; custom fonts only when core to the brand | | Logo | Only if the app aggregates content from multiple sources — and always top-right | | Text bans | ❌ Instructional text ("tap to refresh") · ❌ "last updated/checked" language | | Appearance | Support both light and dark | | Placeholder | Ship a placeholder state (blocked shapes where content will be) for pre-data loading |
TimelineEntryRelevance) so yours surfaces at the right moment.After generation, provide:
MyAppWidgets/
├── {Name}Widget.swift # Widget definition + configuration
├── {Name}TimelineProvider.swift # Timeline provider with placeholder/snapshot/timeline
├── {Name}Entry.swift # TimelineEntry data model
├── {Name}WidgetViews.swift # Size-specific views for each family
├── {Name}AppIntent.swift # (if configurable/interactive) App Intent
└── (update WidgetBundle if needed)
Shared/
└── {Name}DataProvider.swift # (if App Groups) Shared data access
1. Add the widget extension target (if not present):
2. Enable App Groups (if sharing data with the main app):
group.com.yourcompany.yourapp)3. Register the widget in the WidgetBundle:
@main
struct MyAppWidgets: WidgetBundle {
var body: some Widget {
// Existing widgets...
{Name}Widget()
}
}
4. Trigger widget updates from the main app when data changes:
import WidgetKit
// Reload a specific widget
WidgetCenter.shared.reloadTimelines(ofKind: "{Name}Widget")
// Or reload all widgets
WidgetCenter.shared.reloadAllTimelines()
5. For App Group data sharing, write from the main app:
let sharedDefaults = UserDefaults(suiteName: "group.com.yourcompany.yourapp")
sharedDefaults?.set(encodedData, forKey: "widgetData")
// Then trigger reload
WidgetCenter.shared.reloadTimelines(ofKind: "{Name}Widget")
#Preview with timeline entry data for rapid iteration.WidgetCenter.shared.getCurrentConfigurations to verify registered widgets..after(nextEventDate) policyButton(intent:) for each action (iOS 17+)Text(date, style: .timer) / Text(date, style: .relative) for automatic live updatescontainerBackground required (iOS 17+): All widget views must use .containerBackground(for: .widget) to support the system's removable background feature. Without this, widgets show a default placeholder background.AccessoryWidgetBackground() for backgrounds and keep designs simple with high contrast.Text(date, style: .timer) for countdowns; the system animates these for you.getTimeline must complete quickly. The system may terminate long-running providers.@main conflict: Only one @main per widget extension. If you have multiple widgets, use a WidgetBundle as the single @main entry point.AppIntent parameter values are stored by the system. Do not rely on UserDefaults for configuration state.#Preview(as: .systemSmall) for family-specific widget previews.development
US web checkout via the StoreKit External Purchase Link entitlement — currently 0% Apple commission (litigation ongoing), how to ship it safely, and how to architect for a commission flip so a future ruling is a config change, not a rewrite. Use when adding external purchase links, weighing web checkout vs IAP, or planning US-storefront pricing strategy.
tools
Revenue beyond the single-app price tag — own-app bundles, Family Sharing as a conversion lever, cross-developer bundles & suites, and institutional licensing via Group Purchases / Apple School & Business Manager. Use when a developer has multiple apps, a subscription worth sharing, complementary indie partners, or school/clinic/business buyers.
testing
Run a structured accessibility audit on an iOS/macOS app — automated XCUITest audits, Accessibility Inspector, manual VoiceOver/Dynamic Type passes, and App Store Accessibility Nutrition Label evaluation. Use before release, when preparing Nutrition Label declarations, or for EU Accessibility Act compliance.
tools
Stage-by-stage audit of an app's App Store growth machinery against a 54-item P0–P9 playbook — every item scored from an App Store Connect MCP call, a codebase check, or an explicit question to the user, then routed to the skill or command that fixes it. Read-only on App Store Connect. Use for a growth audit or scorecard, a pre-launch growth plan, a quarterly re-audit, or "which growth levers am I missing."