Install any skill in seconds. Free to start, no credit card required.
Get Started Free →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.
.claude/skills/rshankras-widget-generator/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-09 | ✗→✓ | ▲ Improved | 118% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 243% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 201% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 101% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 130% | 0% |
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:
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 widgetWidgetCenter.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 configurationWidget struct with StaticConfiguration or AppIntentConfiguration{Name}TimelineProvider.swift -- Timeline logicTimelineProvider (static) or AppIntentTimelineProvider (configurable){Name}Entry.swift -- Timeline entry modelTimelineEntry struct with date and display data{Name}WidgetViews.swift -- Size-specific viewscontainerBackground 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 access1. 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:
swift@main struct MyAppWidgets: WidgetBundle { var body: some Widget { // Existing widgets... {Name}Widget() } }
4. Trigger widget updates from the main app when data changes:
swiftimport 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:
swiftlet 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.Other measured skills in the registry, with their headline benchmark lift.