{"id":5614,"date":"2025-07-27T09:50:41","date_gmt":"2025-07-27T13:50:41","guid":{"rendered":"https:\/\/stepinto.vision\/?p=5614"},"modified":"2025-07-27T09:50:42","modified_gmt":"2025-07-27T13:50:42","slug":"widgets-getting-started-with-visionos-widgets","status":"publish","type":"post","link":"https:\/\/stepinto.vision\/example-code\/widgets-getting-started-with-visionos-widgets\/","title":{"rendered":"Widgets &#8211; Getting started with visionOS Widgets"},"content":{"rendered":"\n<p>Four key concepts that make widgets so compelling on visionOS.<\/p>\n\n\n\n<p>Widgets on one of the best new features coming in visionOS 26. They provide a vital and previously missing level of continuity. Widgets can be useful, decorative, interactive, and just plain playful. Let&#8217;s dive in with the basics, then a handful concepts.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Widget Basics<\/h2>\n\n\n\n<p>To add a widget to an existing project, go to File > New > Target&#8230; <\/p>\n\n\n\n<p>With the visionOS template filter selected, look for Widget Extension and add it to your project. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"731\" data-attachment-id=\"5617\" data-permalink=\"https:\/\/stepinto.vision\/example-code\/widgets-getting-started-with-visionos-widgets\/attachment\/2025-07-27-widgets-01-01\/\" data-orig-file=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-01.png?fit=1424%2C1016&amp;ssl=1\" data-orig-size=\"1424,1016\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"2025.07.27-widgets-01-01\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-01.png?fit=1024%2C731&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-01.png?resize=1024%2C731&#038;ssl=1\" alt=\"\" class=\"wp-image-5617\" srcset=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-01.png?resize=1024%2C731&amp;ssl=1 1024w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-01.png?resize=300%2C214&amp;ssl=1 300w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-01.png?resize=768%2C548&amp;ssl=1 768w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-01.png?resize=1200%2C856&amp;ssl=1 1200w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-01.png?w=1424&amp;ssl=1 1424w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Adding a Widget Extension<\/figcaption><\/figure>\n\n\n\n<p>This will add a new target to your Xcode project with some template files to get you started.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>An AppIntents file for configuration<\/li>\n\n\n\n<li>A WidgetBundle where we can add one or more widgets<\/li>\n\n\n\n<li>An example file with multiple structs that make up a widget<\/li>\n<\/ul>\n\n\n\n<p>We can switch Xcode to build this target and run it in the Simulator.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"314\" data-attachment-id=\"5619\" data-permalink=\"https:\/\/stepinto.vision\/example-code\/widgets-getting-started-with-visionos-widgets\/attachment\/2025-07-27-widgets-01-02\/\" data-orig-file=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-02.png?fit=1526%2C468&amp;ssl=1\" data-orig-size=\"1526,468\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"2025.07.27-widgets-01-02\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-02.png?fit=1024%2C314&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-02.png?resize=1024%2C314&#038;ssl=1\" alt=\"\" class=\"wp-image-5619\" srcset=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-02.png?resize=1024%2C314&amp;ssl=1 1024w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-02.png?resize=300%2C92&amp;ssl=1 300w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-02.png?resize=768%2C236&amp;ssl=1 768w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-02.png?resize=1200%2C368&amp;ssl=1 1200w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-02.png?w=1526&amp;ssl=1 1526w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Select the widget target<\/figcaption><\/figure>\n\n\n\n<p>Building and testing widgets in the Simulator is perfect for quick iterations. The visionOS 26 beta has a dedicated Widgets app. After running your widget, open this app and look for it in the sidebar. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" data-attachment-id=\"5621\" data-permalink=\"https:\/\/stepinto.vision\/example-code\/widgets-getting-started-with-visionos-widgets\/attachment\/2025-07-27-widgets-01-03\/\" data-orig-file=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-03.jpeg?fit=3840%2C2160&amp;ssl=1\" data-orig-size=\"3840,2160\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"2025.07.27-widgets-01-03\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-03.jpeg?fit=1024%2C576&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-03.jpeg?resize=1024%2C576&#038;ssl=1\" alt=\"\" class=\"wp-image-5621\" srcset=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-03.jpeg?resize=1024%2C576&amp;ssl=1 1024w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-03.jpeg?resize=300%2C169&amp;ssl=1 300w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-03.jpeg?resize=768%2C432&amp;ssl=1 768w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-03.jpeg?resize=1536%2C864&amp;ssl=1 1536w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-03.jpeg?resize=2048%2C1152&amp;ssl=1 2048w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-03.jpeg?resize=1200%2C675&amp;ssl=1 1200w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-03.jpeg?w=2580&amp;ssl=1 2580w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">StepIntoWidgets selected in the Widgets app.<\/figcaption><\/figure>\n\n\n\n<p>From here we can tap Add Widget. This will add the current version to next to this window. A few notes about working in the Simulator.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The Simulator doesn&#8217;t support walls, so we can&#8217;t snap and lock them to surfaces.<\/li>\n\n\n\n<li>Sometimes the widget may not update after running it. Simply remove it and re-add it.<\/li>\n\n\n\n<li>Sometimes the widget preview may not update after running it. Simply select another widget, then select your widget again in the sidebar.<\/li>\n<\/ul>\n\n\n\n<p>As of Xcode Beta 4, widgets seem to update their content anytime I run the app, but your experience may differ from mine.<\/p>\n\n\n\n<p>We&#8217;ll add custom widget content in some future examples. For now, let&#8217;s use the &#8220;Favorite Emoji&#8221; example from the template and focus on some features. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Widget Size<\/h2>\n\n\n\n<p>We can use <code>supportedFamilies<\/code> to define an array of sizes for a widget. Not all sizes are supported on visionOS. As of visionOS Beta 4 we can use: <code>[.systemSmall, .systemMedium, .systemExtraLargePortrait]<\/code>. No one really understands why Apple excluded the large square <code>.systemLarge<\/code> from visionOS. Instead, we are encouraged to use <code>.systemExtraLargePortrait<\/code>, which is new for visionOS.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(0, 0, 0, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>struct SimpleWidgets: Widget {\n    let kind: String = \"SimpleWidgets\"\n\n    var body: some WidgetConfiguration {\n        AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in\n            SimpleWidgetsEntryView(entry: entry)\n                .containerBackground(.white.gradient, for: .widget)\n        }\n        .supportedFamilies(&#91;.systemSmall, .systemMedium, .systemExtraLargePortrait&#93;)\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #0000FF\">struct<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #267F99\">SimpleWidgets<\/span><span style=\"color: #000000\">: Widget {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">let<\/span><span style=\"color: #000000\"> kind: <\/span><span style=\"color: #267F99\">String<\/span><span style=\"color: #000000\"> = <\/span><span style=\"color: #A31515\">&quot;SimpleWidgets&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> body: some WidgetConfiguration {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #795E26\">AppIntentConfiguration<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">kind<\/span><span style=\"color: #000000\">: kind, <\/span><span style=\"color: #795E26\">intent<\/span><span style=\"color: #000000\">: ConfigurationAppIntent.self, <\/span><span style=\"color: #795E26\">provider<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #795E26\">Provider<\/span><span style=\"color: #000000\">()) { entry <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">SimpleWidgetsEntryView<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">entry<\/span><span style=\"color: #000000\">: entry)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                .<\/span><span style=\"color: #795E26\">containerBackground<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">white<\/span><span style=\"color: #000000\">.<\/span><span style=\"color: #001080\">gradient<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">for<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">widget<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">supportedFamilies<\/span><span style=\"color: #000000\">(&#91;.<\/span><span style=\"color: #001080\">systemSmall<\/span><span style=\"color: #000000\">, .<\/span><span style=\"color: #001080\">systemMedium<\/span><span style=\"color: #000000\">, .<\/span><span style=\"color: #001080\">systemExtraLargePortrait<\/span><span style=\"color: #000000\">&#93;)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Mounting Styles<\/h2>\n\n\n\n<p>We can use <code>.supportedMountingStyles<\/code> to support <code>.elevated<\/code> (default) or <code>.recessed<\/code> (new) mounting styles. If you support both styles, then users can pick the one they want when configuring the widget. Some widgets may only make sense in one or the other style. For example, Apple uses <code>.recessed<\/code> on the Weather widget to make it feel more like a window or portal.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(0, 0, 0, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>struct SimpleWidgets: Widget {\n    let kind: String = \"SimpleWidgets\"\n\n    var body: some WidgetConfiguration {\n        AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in\n            SimpleWidgetsEntryView(entry: entry)\n                .containerBackground(.white.gradient, for: .widget)\n        }\n        .supportedFamilies(&#91;.systemSmall, .systemMedium, .systemExtraLargePortrait&#93;)\n        .supportedMountingStyles(&#91;.elevated, .recessed&#93;)\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #0000FF\">struct<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #267F99\">SimpleWidgets<\/span><span style=\"color: #000000\">: Widget {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">let<\/span><span style=\"color: #000000\"> kind: <\/span><span style=\"color: #267F99\">String<\/span><span style=\"color: #000000\"> = <\/span><span style=\"color: #A31515\">&quot;SimpleWidgets&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> body: some WidgetConfiguration {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #795E26\">AppIntentConfiguration<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">kind<\/span><span style=\"color: #000000\">: kind, <\/span><span style=\"color: #795E26\">intent<\/span><span style=\"color: #000000\">: ConfigurationAppIntent.self, <\/span><span style=\"color: #795E26\">provider<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #795E26\">Provider<\/span><span style=\"color: #000000\">()) { entry <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">SimpleWidgetsEntryView<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">entry<\/span><span style=\"color: #000000\">: entry)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                .<\/span><span style=\"color: #795E26\">containerBackground<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">white<\/span><span style=\"color: #000000\">.<\/span><span style=\"color: #001080\">gradient<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">for<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">widget<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">supportedFamilies<\/span><span style=\"color: #000000\">(&#91;.<\/span><span style=\"color: #001080\">systemSmall<\/span><span style=\"color: #000000\">, .<\/span><span style=\"color: #001080\">systemMedium<\/span><span style=\"color: #000000\">, .<\/span><span style=\"color: #001080\">systemExtraLargePortrait<\/span><span style=\"color: #000000\">&#93;)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">supportedMountingStyles<\/span><span style=\"color: #000000\">(&#91;.<\/span><span style=\"color: #001080\">elevated<\/span><span style=\"color: #000000\">, .<\/span><span style=\"color: #001080\">recessed<\/span><span style=\"color: #000000\">&#93;)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Texture<\/h2>\n\n\n\n<p>We can use <code>widgetTexture<\/code> to select a texture that suits our design. Currently we can choose from <code>.glass<\/code> and <code>.paper<\/code>. The paper variant looks really good when viewed on device. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(0, 0, 0, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>struct SimpleWidgets: Widget {\n    let kind: String = \"SimpleWidgets\"\n\n    var body: some WidgetConfiguration {\n        AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in\n            SimpleWidgetsEntryView(entry: entry)\n                .containerBackground(.white.gradient, for: .widget)\n        }\n        .supportedFamilies(&#91;.systemSmall, .systemMedium, .systemExtraLargePortrait&#93;)\n        .supportedMountingStyles(&#91;.elevated, .recessed&#93;)\n        .widgetTexture(.paper) \/\/ or .glass\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #0000FF\">struct<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #267F99\">SimpleWidgets<\/span><span style=\"color: #000000\">: Widget {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">let<\/span><span style=\"color: #000000\"> kind: <\/span><span style=\"color: #267F99\">String<\/span><span style=\"color: #000000\"> = <\/span><span style=\"color: #A31515\">&quot;SimpleWidgets&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> body: some WidgetConfiguration {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #795E26\">AppIntentConfiguration<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">kind<\/span><span style=\"color: #000000\">: kind, <\/span><span style=\"color: #795E26\">intent<\/span><span style=\"color: #000000\">: ConfigurationAppIntent.self, <\/span><span style=\"color: #795E26\">provider<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #795E26\">Provider<\/span><span style=\"color: #000000\">()) { entry <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">SimpleWidgetsEntryView<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">entry<\/span><span style=\"color: #000000\">: entry)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                .<\/span><span style=\"color: #795E26\">containerBackground<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">white<\/span><span style=\"color: #000000\">.<\/span><span style=\"color: #001080\">gradient<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">for<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">widget<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">supportedFamilies<\/span><span style=\"color: #000000\">(&#91;.<\/span><span style=\"color: #001080\">systemSmall<\/span><span style=\"color: #000000\">, .<\/span><span style=\"color: #001080\">systemMedium<\/span><span style=\"color: #000000\">, .<\/span><span style=\"color: #001080\">systemExtraLargePortrait<\/span><span style=\"color: #000000\">&#93;)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">supportedMountingStyles<\/span><span style=\"color: #000000\">(&#91;.<\/span><span style=\"color: #001080\">elevated<\/span><span style=\"color: #000000\">, .<\/span><span style=\"color: #001080\">recessed<\/span><span style=\"color: #000000\">&#93;)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">widgetTexture<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">paper<\/span><span style=\"color: #000000\">) <\/span><span style=\"color: #008000\">\/\/ or .glass<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Level of Detail<\/h2>\n\n\n\n<p>Widgets on visionOS can have two versions. A detailed (default) version to display when a user is nearby and a simplified version. We don&#8217;t have to support the simplified version if we don&#8217;t need it, but it can be a nice way to reduce visual clutter and noise. Apple uses level of detail in the poster-sized music widgets. When viewed from far away, this widget shows album art, title, and artist. When we approach it, the widget shifts to the default view and shows more information such as a list of songs for the album.<\/p>\n\n\n\n<p>To support level of detail, we can import it from the environment, the switch on the cases.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(2 * 0.6 * .875rem);--cbp-line-highlight-color:rgba(0, 0, 0, 0.2);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>struct SimpleWidgetsEntryView : View {\n    var entry: Provider.Entry\n    @Environment(\\.levelOfDetail) var levelOfDetail: LevelOfDetail\n\n    var body: some View {\n        switch levelOfDetail {\n        case .simplified:\n            VStack {\n                Text(entry.date, style: .time)\n                Text(entry.configuration.favoriteEmoji)\n            }\n        default:\n            VStack {\n                Text(\"Time:\")\n                Text(entry.date, style: .time)\n\n                Text(\"Favorite Emoji:\")\n                Text(entry.configuration.favoriteEmoji)\n            }\n        }\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #0000FF\">struct<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #267F99\">SimpleWidgetsEntryView<\/span><span style=\"color: #000000\"> : View {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> entry: Provider.Entry<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">@Environment<\/span><span style=\"color: #000000\">(\\.<\/span><span style=\"color: #001080\">levelOfDetail<\/span><span style=\"color: #000000\">) <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> levelOfDetail: LevelOfDetail<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> body: some View {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #000000\">        <\/span><span style=\"color: #AF00DB\">switch<\/span><span style=\"color: #000000\"> levelOfDetail {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #000000\">        <\/span><span style=\"color: #AF00DB\">case<\/span><span style=\"color: #000000\"> .<\/span><span style=\"color: #001080\">simplified<\/span><span style=\"color: #000000\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            VStack {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(entry.<\/span><span style=\"color: #001080\">date<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">style<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">time<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(entry.<\/span><span style=\"color: #001080\">configuration<\/span><span style=\"color: #000000\">.<\/span><span style=\"color: #001080\">favoriteEmoji<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #000000\">        <\/span><span style=\"color: #AF00DB\">default<\/span><span style=\"color: #000000\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            VStack {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #A31515\">&quot;Time:&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(entry.<\/span><span style=\"color: #001080\">date<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">style<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">time<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #A31515\">&quot;Favorite Emoji:&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(entry.<\/span><span style=\"color: #001080\">configuration<\/span><span style=\"color: #000000\">.<\/span><span style=\"color: #001080\">favoriteEmoji<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Recap<\/h2>\n\n\n\n<p>We learned how to create a widget and we saw four concepts that make widgets so compelling on visionOS. In the next post we&#8217;ll start adding out own content.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Four key concepts that make widgets so compelling on visionOS.<\/p>\n","protected":false},"author":93705089,"featured_media":5629,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_EventAllDay":false,"_EventTimezone":"","_EventStartDate":"","_EventEndDate":"","_EventStartDateUTC":"","_EventEndDateUTC":"","_EventShowMap":false,"_EventShowMapLink":false,"_EventURL":"","_EventCost":"","_EventCostDescription":"","_EventCurrencySymbol":"","_EventCurrencyCode":"","_EventCurrencyPosition":"","_EventDateTimeSeparator":"","_EventTimeRangeSeparator":"","_EventOrganizerID":[],"_EventVenueID":[],"_OrganizerEmail":"","_OrganizerPhone":"","_OrganizerWebsite":"","_VenueAddress":"","_VenueCity":"","_VenueCountry":"","_VenueProvince":"","_VenueState":"","_VenueZip":"","_VenuePhone":"","_VenueURL":"","_VenueStateProvince":"","_VenueLat":"","_VenueLng":"","_VenueShowMap":false,"_VenueShowMapLink":false,"_kadence_starter_templates_imported_post":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false},"categories":[1365],"tags":[],"class_list":["post-5614","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-example-code"],"jetpack_publicize_connections":[],"taxonomy_info":{"category":[{"value":1365,"label":"Example Code"}]},"featured_image_src_large":["https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-04.jpeg?fit=1024%2C576&ssl=1",1024,576,true],"author_info":{"display_name":"Joseph Simpson","author_link":"https:\/\/stepinto.vision\/author\/vrhermit\/"},"comment_info":0,"category_info":[{"term_id":1365,"name":"Example Code","slug":"example-code","term_group":0,"term_taxonomy_id":11,"taxonomy":"category","description":"Code snippets and examples of using common APIs throughout visionOS development","parent":0,"count":187,"filter":"raw","cat_ID":1365,"category_count":187,"category_description":"Code snippets and examples of using common APIs throughout visionOS development","cat_name":"Example Code","category_nicename":"example-code","category_parent":0}],"tag_info":false,"jetpack_featured_media_url":"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/07\/2025.07.27-widgets-01-04.jpeg?fit=3840%2C2160&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/5614","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/users\/93705089"}],"replies":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/comments?post=5614"}],"version-history":[{"count":12,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/5614\/revisions"}],"predecessor-version":[{"id":5630,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/5614\/revisions\/5630"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/media\/5629"}],"wp:attachment":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/media?parent=5614"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/categories?post=5614"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/tags?post=5614"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}