How to build a configurable widget with WidgetKit and SwiftUI
Learn how to allow users to customize their widgets.
05 Sep 2022 · 4 min read
In the previous article on building widgets for iOS applications with WidgetKit and SwiftUI, we looked at the basics on how to develop widgets that are not dependent on any user properties.
In this article, we'll dive into widgets that display content depending on some user input like their location, their preferences or any other input that allows users to customize their widget.

Steps to support configurable widgets
To add configurable properties to a widget, the following steps are required:
- Adding a custom intent definition that defines configurable properties.
- Configuring the widget by using IntentConfiguration.
- Optionally implementing an Intents extension in case the properties depend on dynamic data.
Adding a custom intent definition
As a first step, we add an .intentdefinition file to the Xcode project by selecting File > New File > SiriKit Intent Definition File.

When selecting the intent definition file, Xcode shows an intent definition editor where we can configure parameters that allow users to customize their widgets.
Parameters can be:
- a static list of choices
- generated dynamically
To provide a static list of choices, we can choose the Add Enum menu item to create a static enumeration.

If the choices can very, we can provide dynamic data by generating a new type.

Adding an Intents Extension
To provide data dynamically, we need to add am Intents extension by following those steps:
- Select File > New > Target > Intents extension in Xcode's menu.
- Enter a name and select none for Starting Point.
- Choose Activate when Xcode prompts about activating the new scheme.
- Add the intent we created earlier in the Supported Intents section in the General tab of the extension's target.

- Make sure that the app, the widget extension and the Intents extension all include the .intentdefinition file in the Target Membership section.

Implementing an intent handler
When adding an Intent extension, Xcode created a IntentHandler.swift file for us. We'll extend this handler to provide values for the widget's customization. Based on the custom intent definition file, Xcode generates a protocol, SelectCategoryIntentHandling, that the handler must conform to.
class IntentHandler: INExtension, SelectCategoryIntentHandling {func provideCategoryOptionsCollection(for intent: SelectCategoryIntent, with completion: @escaping (INObjectCollection<NSString>?, Error?) -> Void) {let categories = WidgetQuotesCategory.allCases.map { QuotesCategory(identifier: $0.identifier, display: $0.title) }completion((INObjectCollection(items: categories))}override func handler(for intent: INIntent) -> Any {return self}}
In the provideCategoryOptionsCollection method, we provide available categories.
Handling custom values
Once users edit a widget and select a category, the next step is to reflect their choice in the widget's content. Instead of a TimelineProvider like we used in the previous article on building widgets for iOS applications with WidgetKit and SwiftUI, we now use an IntentTimelineProvider.
func getTimeline(for configuration: SelectCategoryIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {loadQuoteOfTheDay(for: configuration.category) { quoteOfTheDay inlet entry = ExampleTimelineEntry(date: Date(), quoteOfTheDay: quoteOfTheDay)let timeline = Timeline(entries: [entry], policy: .after(Date.tomorrow) )completion(timeline)}}
The only difference is that now we get the SelectCategoryIntent passed in as parameter, so we can access the selected category and provide appropriate results.

Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips