{"version":"https://jsonfeed.org/version/1","title":"Aaron Gustafson: Content tagged Microsoft","description":"The latest 20 posts and links tagged Microsoft.","home_page_url":"https://www.aaron-gustafson.com","feed_url":"https://www.aaron-gustafson.com/feeds/microsoft.json","author":{"name":"Aaron Gustafson","url":"https://www.aaron-gustafson.com"},"icon":"https://www.aaron-gustafson.com/i/og-logo.png","favicon":"https://www.aaron-gustafson.com/favicon.png","expired":false,"items":[{"id":"https://www.aaron-gustafson.com/notebook/accessibility-assistant-for-figma-v52/","title":"✍🏻 Accessibility Assistant for Figma v52","summary":"I just hit “publish” on Accessibility Assistant for Figma v52 and I wanted to share some details on why this is a monumental release for us.","content_html":"<p>I just hit “publish” on <a href=\"https://www.figma.com/community/plugin/731310036968334777/accessibility-assistant\">Accessibility Assistant for Figma</a> v52 and I wanted to share some details on why this is a monumental release for us.</p>\n<p>We’re in the process of a major overhaul to this plugin. There was a lot of infrastructural work to do to modernize the plugin and set the stage for a host of new features to make designers more productive when it comes to making their designs more accessible. This release incorporates a lot of that foundational work, notably:</p>\n<ul>\n<li>Annotations are now presented as Figma-native Dev Mode annotations; this greatly reduces the working overhead of the plugin and reduces visual clutter in the document. We’ve also color-coordinated the icons in the Annotation Set viewer to the labels you see in the Dev Mode annotations, making it easier to scan.</li>\n<li>Legacy annotation tables will automatically be migrated into the new system. The visual readout tables will be hidden when this happens, but are still accessible if you need to copy or reference them. We’ve also included a tool to clean up these old layers when you’re ready.</li>\n<li>Annotations are now managed in a single UI rather than being separated, based on whether they impact focus order. This means you don’t need to jump back &amp; forth between tools to properly annotate your designs.</li>\n<li>We’ve organized and expanded the list of W3C roles available in the role picker. Additionally, the form now adapts to the role, offering you only the relevant fields and reducing distraction. We also added a description field, should you need it.</li>\n</ul>\n<p>We also fixed bugs related to duplicating layers. You can now copy layers and the annotations will go along for the ride, becoming a new Annotation Set. Similarly, you can now duplicate pages and the annotations — which are page-bound — will be re-generated. It’s worth noting that this may take some time on particularly large pages.</p>\n<p>This release has been a long time coming, but I’m incredibly proud of the team that’s been working so diligently on this, particularly Ashish Singh from HCL and Michael Fairchild, Scott O’Hara, and Ben Truelove from Microsoft. Their attention to detail and encyclopedic knowledge of accessibility has been instrumental in getting this project to the place that it is.</p>\n<p>And there’s more to come!</p>\n","social_text":"I just hit “publish” on Accessibility Assistant for Figma v52 and I wanted to share some details on why this is a monumental release for us.","url":"https://www.aaron-gustafson.com/notebook/accessibility-assistant-for-figma-v52/","tags":["accessibility","design","inclusive design","Microsoft","user experience","WAI-ARIA"],"date_published":"2026-02-20T23:27:28Z"},{"id":"https://www.aaron-gustafson.com/notebook/links/accessibility-training-at-microsoft/","title":"🔗 Accessibility Training at Microsoft","content_html":"<p>At Microsoft, we’ve invested a lot into accessibility upskilling across the company. And now we’ve made our Accessibility Fundamentals learning path freely available to the world to take, either on MS Learn or within another learning environment via its SCORM (Sharable Content Object Reference Model) course package.</p>\n","social_text":"Microsoft’s #Accessibility Fundamentals learning path is now free for everyone","url":"https://www.aaron-gustafson.com/notebook/links/accessibility-training-at-microsoft/","external_url":"https://blogs.microsoft.com/accessibility/accessibility-training-at-microsoft/","tags":["accessibility","Microsoft"],"date_published":"2024-04-30T20:24:04Z"},{"id":"https://www.aaron-gustafson.com/notebook/widgets/","title":"✍🏻 Widgets!","summary":"I finally had a chance to put the work I did on a widgets proposal for PWAs into practice on my own site. It’s pretty exciting!","content_html":"<p>It was a long time coming, but I finally had a chance to put the work I did on <a href=\"https://github.com/MicrosoftEdge/MSEdgeExplainers/tree/main/PWAWidgets\">a widgets proposal for PWAs</a> into practice on my own site. I’m pretty excited about it!</p>\n<h2 id=\"where-it-all-started\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#where-it-all-started\" aria-hidden=\"true\">#</a> Where it all started</h2>\n<p>I had <a href=\"https://web.archive.org/web/20200929174844/https://discourse.wicg.io/t/noodling-on-an-idea-projections-for-web-apps/3900\">the original idea for “projections”</a> way back in 2019. Inspired by <a href=\"https://en.wikipedia.org/wiki/Dashboard_(macOS)#Widget_functions_and_capabilities\">OS X’s Dashboard Widgets</a> and <a href=\"https://en.wikipedia.org/wiki/Adobe_AIR\">Adobe AIR</a>, I’d begun to wonder if it might be possible to <em>project</em> a component from a website into those kinds of surfaces. Rather than building a bespoke widget that connected to an API, I thought it made sense to leverage an installed PWA to manage those “projections.” I shared the idea at TPAC that year and got some interest from a broad range of folks, but didn’t have much time to work on the details until a few years later.</p>\n<p>In the intervening time, I kept working through the concept in my head. I mean in an ideal world, the widget would just be a responsive web page, right? But if that were the case, what happens when every widget loads the entirety of React to render their stock ticker? That seemed like a performance nightmare.</p>\n<p>In my gut, I felt like the right way to build things would be to have a standard library of widget templates and to enable devs to flow data into them via a Service Worker. Alex Russell suggested I model the APIs on how Notifications are handled (since they serve a similar function) and I was off to the races.</p>\n<p>I drafted <a href=\"https://github.com/aarongustafson/pwa-widgets\">a substantial proposal for my vision of how PWA widgets should work</a>. Key aspects included:</p>\n<ul>\n<li>A declarative way to define and configure a widget from within the Web App Manifest;</li>\n<li>A progressively enhanced pathway for devs to design a widget that adapts to its host environment, from using predefined templates to using custom templates to full-blown web-based widgets (with rendering akin to an <code>iframe</code>);</li>\n<li>A collection of recommended stock templates that implementors should offer to support most widget types;</li>\n<li>Extensibility to support custom templates using any of a variety of templating languages; and</li>\n<li>A complete suite of tools for managing widgets and any associated business logic within a Service Worker.</li>\n</ul>\n<h2 id=\"widgets-became-a-reality\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#widgets-became-a-reality\" aria-hidden=\"true\">#</a> Widgets became a reality</h2>\n<p>After continuing to gently push on this idea with colleagues across Microsoft (and beyond), I discovered that the Windows 11 team was looking to open up the new Widget Dashboard to third-party applications. I saw this as an opportunity to turn my idea into a reality. After working my way into the conversation, I made a solid case for why PWAs needed to be a part of that story and… it worked! (It no doubt helped that companies including Meta, Twitter, and Hulu were all invested in PWA as a means of delivering apps for Windows.)</p>\n<p>While the timeline for implementation didn’t allow us to tackle the entirety of my proposal, we did carve out the pieces that made for a compelling MVP. This allowed us to show what’s possible, see how folks use it, and plan for future investment in the space.</p>\n<p>Sadly, it meant tabling two features I really loved:</p>\n<ul>\n<li><strong>Stock/predefined templates</strong>. A library of lightly theme-able, consistent, cross-platform templates based on common data structures (e.g., RSS/Atom, iCal) would make it incredibly simple for devs to build a widget. If implemented well, devs might not even need to write a single line of business logic in their Service Worker as the browser could pick up all of the configuration details from the Manifest.</li>\n<li><strong>Configurable widget instances.</strong> Instead of singleton widgets, these would allow you to define a single widget type and replicate it for different use cases. For example, a widget to follow a social media user’s profile could be defined once and the individual instances could be configured with the specific account to be followed.</li>\n</ul>\n<p>I’m sincerely hopeful these two features eventually make their way to us as I think they truly unlock the power of the widget platform. Perhaps, with enough uptake on the current implementation, we can revisit these in the not-too-distant future.</p>\n<hr>\n<p>To test things out, I decided to build two widgets for this site:</p>\n<ol>\n<li>Latest posts</li>\n<li>Latest links</li>\n</ol>\n<p>Both are largely the same in terms of their setup: They display a list of linked titles from this site.</p>\n<h2 id=\"designing-my-widget-templates\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#designing-my-widget-templates\" aria-hidden=\"true\">#</a> Designing my widget templates</h2>\n<p>Given that they were going to be largely identical, I made <a href=\"https://github.com/aarongustafson/aaron-gustafson.com/blob/main/src/static/w/feed.ac.json\">a single “feed” template for use in both widgets</a>. The templating tech I used is called <a href=\"https://adaptivecards.io\">Adaptive Cards</a>, which is what Windows 11 uses for rendering.</p>\n<p>Adaptive Card templates are relatively straightforward JSON:</p>\n<pre class=\"language-json\" tabindex=\"0\"><code class=\"language-json\">&amp;#<span class=\"token number\">123</span>;\n  <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"AdaptiveCard\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"$schema\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"http://adaptivecards.io/schemas/adaptive-card.json\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"1.6\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"body\"</span><span class=\"token operator\">:</span> &amp;#<span class=\"token number\">91</span>;\n    &amp;#<span class=\"token number\">123</span>;\n      <span class=\"token property\">\"$data\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"$&amp;#123;take(items,5)&amp;#125;\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Container\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"items\"</span><span class=\"token operator\">:</span> &amp;#<span class=\"token number\">91</span>;\n        &amp;#<span class=\"token number\">123</span>;\n          <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"TextBlock\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"text\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"&amp;#91;$&amp;#123;title&amp;#125;&amp;#93;($&amp;#123;url&amp;#125;)\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"wrap\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"weight\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Bolder\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"spacing\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Padding\"</span><span class=\"token punctuation\">,</span>\n          <span class=\"token property\">\"height\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"stretch\"</span>\n        &amp;#<span class=\"token number\">125</span>;\n      &amp;#<span class=\"token number\">93</span>;<span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"height\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"stretch\"</span>\n    &amp;#<span class=\"token number\">125</span>;\n  &amp;#<span class=\"token number\">93</span>;<span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"backgroundImage\"</span><span class=\"token operator\">:</span> &amp;#<span class=\"token number\">123</span>;\n    <span class=\"token property\">\"url\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://www.aaron-gustafson.com/i/background-logo.png\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"verticalAlignment\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Bottom\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"horizontalAlignment\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Center\"</span>\n  &amp;#<span class=\"token number\">125</span>;\n&amp;#<span class=\"token number\">125</span>;</code></pre>\n<p>What this structure does is:</p>\n<ol>\n<li>Create a container into which I will place the content;</li>\n<li>Extract the first five <code>items</code> from the data being fed into the template (more on that in a moment);</li>\n<li>Loop through each <code>item</code> and\n<ul>\n<li>create a text block,</li>\n<li>populate its content with Markdown to generate a linked title (using the <code>title</code> and <code>url</code> keys from the <code>item</code> object)</li>\n<li>Set some basic styles to make the text bold, separate the titles a little and make them grow to fill the container; then, finally</li>\n</ul>\n</li>\n<li>Set a background on the widget.</li>\n</ol>\n<p>The way Adaptive Cards work is that they flow JSON data into a template and render that. The variable names in the template map directly to the incoming data structure, so are totally up to you to define. As these particular widgets are feed-driven and <a href=\"https://www.aaron-gustafson.com/feeds/\">this site already supports JSONFeed</a>, I set up the widgets to flow the appropriate feed into each and used the keys that were already there. For reference, here’s a sample JSONFeed <code>item</code>:</p>\n<pre class=\"language-json\" tabindex=\"0\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"…\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"title\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"…\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"summary\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"…\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"content_html\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"…\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"url\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"…\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"tags\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"date_published\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"…\"</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>If you want to tinker with Adaptive Cards and make your own, you can do so with <a href=\"https://adaptivecards.io/designer/\">their Designer tool</a>.</p>\n<h3 id=\"defining-the-widgets-in-the-manifest\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#defining-the-widgets-in-the-manifest\" aria-hidden=\"true\">#</a> Defining the widgets in the Manifest</h3>\n<p>With a basic template created, the next step was to set up the two widgets in my Manifest. As they both function largely the same, I’ll just focus on the definition for one of them.</p>\n<p>First off, defining widgets in the Manifest is done via the <code>widgets</code> member, which is an array (much like <code>icons</code> and <code>shortcuts</code>). Each widget is represented as an object in that array. Here is the definition for the “latest posts” widget:</p>\n<pre class=\"language-json\" tabindex=\"0\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Latest Posts\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"short_name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Posts\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"tag\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"feed-posts\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"description\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"The latest posts from Aaron Gustafson’s blog\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"template\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"feed\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"ms_ac_template\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/w/feed.ac.json\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"data\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/feeds/latest-posts.json\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"application/json\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"auth\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"update\"</span><span class=\"token operator\">:</span> <span class=\"token number\">21600</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"icons\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"src\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/i/icons/webicon-rss.png\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"image/png\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"sizes\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"120x120\"</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"screenshots\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"src\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/i/screenshots/widget-posts.png\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"sizes\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"387x387\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"label\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"The latest posts widget\"</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>Breaking this down:</p>\n<ol>\n<li><code>name</code> and <code>short_name</code> act much like these keys in the root of the Manifest as well as in <code>shortcuts</code>: The <code>name</code> value is used as the name for the widget unless there’s not enough room, in which case <code>short_name</code> is used.</li>\n<li>You can think of <code>tag</code> as analogous to <code>class</code> in HTML sense. It’s a way of labeling a widget so you can easily reference it later. Each widget instance will have a unique id created by the widget service, but that instance (or all instances, if the widget supports multiple instances) can be accessed via the <code>tag</code>. But more on that later.</li>\n<li>The <code>description</code> key is used for marketing the widget within a host OS or digital storefront. It should accurately (and briefly) describe what the widget does.</li>\n<li>The <code>template</code> key is not currently used in the Windows 11 implementation but refers to the expected standard library widget template provided by the system. As a template library is not currently available, the <code>ms_ac_template</code> value is used to provide a URL to get the custom Adaptive Card (hence “ac”) template. The “ms_” prefix is there because it’s expected that this would be a Microsoft-proprietary property. It follows <a href=\"https://www.w3.org/TR/appmanifest/#proprietary-extensions\">the guidance for extending the Manifest</a>.</li>\n<li>The <code>data</code> and <code>type</code> keys define the path to the data that should be fed into the template for rendering by the widget host and the MIME of the data format it’s in. The Windows 11 implementation currently only accepts JSON data, but the design of widgets is set up to allow for this to eventually extend to other standardized formats like RSS, iCal, vCard, and such.</li>\n<li><code>update</code> is an optional configuration member allowing you to set how often you’d like the widget to update, in seconds. Developers currently need to add the logic for implementing this into their Service Worker, but this setup allows the configuration to remain independent of the JavaScript code, making it easier to maintain.</li>\n<li>Finally, <code>icons</code> and <code>screenshots</code> allow us to define how the widget shows up in the widget host and how it is promoted for install.</li>\n</ol>\n<p>When someone installs my site as a PWA, the information about the available widgets gets ingested by the browser. The browser then determines, based on the provided values and its knowledge of the available widget service(s) on the device, which widgets should be offered. On Windows 11, this information is <a href=\"https://learn.microsoft.com/en-us/windows/apps/develop/widgets/implement-widget-provider-cs#update-the-package-manifest\">routed into the AppXManifest that governs how apps are represented in Windows</a>. The Windows 11 widget service can then read in the details about the available widgets and offer them for users to install.</p>\n<figure id=\"2023-10-09-01\">\n<p><img src=\"https://www.aaron-gustafson.com/i/posts/2023-10-09/widgets-promotion.gif\" alt=\"\"></p>\n<figcaption>An animated capture of Windows 11’s widget promotion surface, showing 2 widgets available from this site’s PWA.</figcaption>\n</figure>\n<h2 id=\"adding-widget-support-to-my-service-worker\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#adding-widget-support-to-my-service-worker\" aria-hidden=\"true\">#</a> Adding widget support to my Service Worker</h2>\n<p>As I mentioned earlier, all of the plumbing for widgets is done within a Service Worker and is modeled on the Notifications API. I’m not going to exhaustively detail how it all works, but I’ll give you enough detail to get you started.</p>\n<p>First off, widgets are exposed via the <code>self.widgets</code> interface. Most importantly, this interface lets you access and update any instances of a widget connected to your PWA.</p>\n<h3 id=\"installing-a-widget\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#installing-a-widget\" aria-hidden=\"true\">#</a> Installing a widget</h3>\n<p>When a user chooses to install a widget, that emits a “widgetinstall” event in your Service Worker. You use that to kickoff the widget lifecycle by gathering the template and data needed to instantiate the widget:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\">self<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"widgetinstall\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Installing </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>event<span class=\"token punctuation\">.</span>widget<span class=\"token punctuation\">.</span>tag<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  event<span class=\"token punctuation\">.</span><span class=\"token function\">waitUntil</span><span class=\"token punctuation\">(</span><span class=\"token function\">initializeWidget</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>widget<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>The event argument comes in with details of the specific widget being instantiated (as <code>event.widget</code>). In the code above, you can see I’ve logged the widget’s <code>tag</code> value to the console. I pass the widget information over to my <code>initializeWidget()</code> function and it updates the widget with the latest data and, if necessary, sets up a <a href=\"https://developer.mozilla.org/docs/Web/API/Web_Periodic_Background_Synchronization_API\">Periodic Background Sync</a>:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">initializeWidget</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">widget</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">await</span> <span class=\"token function\">updateWidget</span><span class=\"token punctuation\">(</span>widget<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">await</span> <span class=\"token function\">registerPeriodicSync</span><span class=\"token punctuation\">(</span>widget<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>The code for my <code>updateWidget()</code> function is as follows:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">updateWidget</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">widget</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> template <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>widget<span class=\"token punctuation\">.</span>definition<span class=\"token punctuation\">.</span>msAcTemplate<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">text</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> data <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>widget<span class=\"token punctuation\">.</span>definition<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">text</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">await</span> self<span class=\"token punctuation\">.</span>widgets<span class=\"token punctuation\">.</span><span class=\"token function\">updateByTag</span><span class=\"token punctuation\">(</span>widget<span class=\"token punctuation\">.</span>definition<span class=\"token punctuation\">.</span>tag<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> template<span class=\"token punctuation\">,</span> data <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Couldn’t update the widget </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>tag<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> e<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>This function does the following:</p>\n<ol>\n<li>Get the template for this widget</li>\n<li>Get the data to flow into the template</li>\n<li>Use the <code>self.widgets.updateByTag()</code> method to push the <var>template</var> and <var>data</var> to the widget service to update any widget instances connected to the widget’s <code>tag</code>.</li>\n</ol>\n<p>As I mentioned, I also have code in place to take advantage of Periodic Background Sync if/when it’s available and the browser allows my site to do it:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">registerPeriodicSync</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">widget</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">let</span> tag <span class=\"token operator\">=</span> widget<span class=\"token punctuation\">.</span>definition<span class=\"token punctuation\">.</span>tag<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token string\">\"update\"</span> <span class=\"token keyword\">in</span> widget<span class=\"token punctuation\">.</span>definition<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    registration<span class=\"token punctuation\">.</span>periodicSync<span class=\"token punctuation\">.</span><span class=\"token function\">getTags</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">tags</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// only one registration per tag</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>tags<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span>tag<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        periodicSync<span class=\"token punctuation\">.</span><span class=\"token function\">register</span><span class=\"token punctuation\">(</span>tag<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token literal-property property\">minInterval</span><span class=\"token operator\">:</span> widget<span class=\"token punctuation\">.</span>definition<span class=\"token punctuation\">.</span>update<span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>This function also receives the widget details and:</p>\n<ol>\n<li>Looks to see if the widget <code>definition</code> (from the Manifest) includes an <code>update</code> member. If it has one, it…</li>\n<li>Checks to see if there’s already a Periodic Background Sync that is registered for this tag. If none exists, it…</li>\n<li>Registers a new Periodic Background Sync using the <code>tag</code> value and a minimum interval equal to the <code>update</code> requested.</li>\n</ol>\n<p>The <code>update</code> member, as you may recall, is the frequency (in seconds) you’d ideally like the widget to be updated. In reality, you’re at the mercy of the browser as to when (or even if) your sync will run, but that’s totally cool as there are other ways to update widgets as well.<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">1</a></sup></p>\n<h3 id=\"uninstalling-a-widget\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#uninstalling-a-widget\" aria-hidden=\"true\">#</a> Uninstalling a widget</h3>\n<p>When a user uninstalls a widget, your Service Worker will receive a “widgetuninstall” event. Much like the “widgetinstall” event, the argument contains details about that widget which you can use to clean up after yourself:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\">self<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"widgetuninstall\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Uninstalling </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>event<span class=\"token punctuation\">.</span>widget<span class=\"token punctuation\">.</span>tag<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  event<span class=\"token punctuation\">.</span><span class=\"token function\">waitUntil</span><span class=\"token punctuation\">(</span><span class=\"token function\">uninstallWidget</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>widget<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Your application may have different cleanup needs, but this is a great time to clean up any unneeded Periodic Sync registrations. Just be sure to check the length of the widget’s <code>instances</code> array (<code>widget.instances</code>) to make sure you’re dealing with the last instance of a given widget <em>before</em> you unregister the sync:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">uninstallWidget</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">widget</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>widget<span class=\"token punctuation\">.</span>instances<span class=\"token punctuation\">.</span>length <span class=\"token operator\">===</span> <span class=\"token number\">1</span> <span class=\"token operator\">&amp;&amp;</span> <span class=\"token string\">\"update\"</span> <span class=\"token keyword\">in</span> widget<span class=\"token punctuation\">.</span>definition<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">await</span> self<span class=\"token punctuation\">.</span>registration<span class=\"token punctuation\">.</span>periodicSync<span class=\"token punctuation\">.</span><span class=\"token function\">unregister</span><span class=\"token punctuation\">(</span>widget<span class=\"token punctuation\">.</span>definition<span class=\"token punctuation\">.</span>tag<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<h3 id=\"refreshing-your-widgets\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#refreshing-your-widgets\" aria-hidden=\"true\">#</a> Refreshing your widgets</h3>\n<p>Widget platforms may periodically freeze your widget(s) to save resources. For example, they may do this when widgets are not visible. To keep your widgets up to date, they will periodically issue a “widgetresume” event. If you’ve modeled your approach on the one I’ve outlined above, you can route this event right through to your <code>updateWidget()</code> function:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\">self<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"widgetresume\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Resuming </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>event<span class=\"token punctuation\">.</span>widget<span class=\"token punctuation\">.</span>tag<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  event<span class=\"token punctuation\">.</span><span class=\"token function\">waitUntil</span><span class=\"token punctuation\">(</span><span class=\"token function\">updateWidget</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>widget<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<h3 id=\"actions\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#actions\" aria-hidden=\"true\">#</a> Actions</h3>\n<p>While I don’t want to get too into the weeds here, I do want to mention that widgets can have predefined user actions as well. These actions result in “widget click” events being sent back to the Service Worker so you can respond to them:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\">self<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"widgetclick\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> widget <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>widget<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> action <span class=\"token operator\">=</span> event<span class=\"token punctuation\">.</span>action<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">switch</span> <span class=\"token punctuation\">(</span>action<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Custom Actions</span>\n    <span class=\"token keyword\">case</span> <span class=\"token string\">\"refresh\"</span><span class=\"token operator\">:</span>\n      event<span class=\"token punctuation\">.</span><span class=\"token function\">waitUntil</span><span class=\"token punctuation\">(</span><span class=\"token function\">updateWidget</span><span class=\"token punctuation\">(</span>widget<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">break</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>For a great example of how a widget can integrate actions, you should check out <a href=\"https://microsoftedge.github.io/Demos/pwamp/\">the demo PWAmp project</a>. <a href=\"https://github.com/MicrosoftEdge/Demos/blob/main/pwamp/sw-widgets.js\">Their Service Worker widget code</a> is worth a read.</p>\n<h2 id=\"result!\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#result!\" aria-hidden=\"true\">#</a> Result!</h2>\n<p>With all of these pieces in place, I was excited to see my site showing up in the Widget Dashboard in Windows 11.</p>\n<figure id=\"2023-10-09-02\">\n<p><img src=\"https://www.aaron-gustafson.com/i/posts/2023-10-09/widgets-in-windows.jpg\" alt=\"\"></p>\n<figcaption>A screenshot of Windows 11 showing the Widget Dashboard overlaying the desktop with this site installed as a PWA to the right. The “latest posts” and “latest links” widgets are shown.</figcaption>\n</figure>\n<p>You can view the full source code on GitHub:</p>\n<ul>\n<li><a href=\"https://github.com/aarongustafson/aaron-gustafson.com/blob/main/src/static/w/feed.ac.json\">“Feed” Adaptive Card Template</a></li>\n<li><a href=\"https://github.com/aarongustafson/aaron-gustafson.com/blob/main/src/static/manifest.json#L158-L237\">Widget definitions in the Manifest</a></li>\n<li><a href=\"https://github.com/aarongustafson/aaron-gustafson.com/blob/main/src/_javascript/serviceworker/widgets.js\">Widgets code in my Service Worker</a></li>\n</ul>\n<hr>\n<p>I’m quite hopeful this will be the first of many places PWA-driven widgets will appear. If you’s like to see them supported elsewhere, be sure to tell your browser and OS vendor(s) of choice. The more they hear from their user base that this feature is needed, the more likely we are to see it get implemented in more places.</p>\n<h2 id=\"addendum%3A-gotchas\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#addendum%3A-gotchas\" aria-hidden=\"true\">#</a> Addendum: Gotchas</h2>\n<p>In wiring this all up, I ran into a few current bugs I wanted to flag so you can avoid them:</p>\n<ul>\n<li>The <code>icons</code> member won’t accept SVG images. This should eventually be fixed, but it was keeping my widgets from appearing as installable.</li>\n<li>The <code>screenshots</code> members can’t be incredibly large. I’m told you should provide square screenshots no larger than 500px ×500px.</li>\n</ul>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<h4 class=\"hidden\">Footnotes</h4>\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>Have you checked out <a href=\"https://developer.mozilla.org/docs/Web/API/Server-sent_events/Using_server-sent_events\">Server Events</a>? <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n","social_text":"I finally had a chance to put the work I did on a widgets proposal for PWAs into practice on my own site. It’s pretty exciting!","url":"https://www.aaron-gustafson.com/notebook/widgets/","tags":["progressive web apps","experiments","JavaScript","Microsoft","this site","user experience","web development","web standards","Windows"],"image":"https://www.aaron-gustafson.com/i/posts/2023-10-09/hero1.jpg","date_published":"2023-10-09T22:38:54Z"},{"id":"https://www.aaron-gustafson.com/appearances/podcasts/2023-01-01-microsoft-ai-for-accessibility/","title":"🎧 Microsoft AI for Accessibility","content_html":"<p>I spent some time talking to Kathryn of <cite>Assembling Inclusion</cite> about the Microsoft AI for Accessibility grant program, the different projects that have been funded, and the future direction of the program.</p>\n","url":"https://anchor.fm/assemblinginclusion/episodes/025-Microsoft-AI-for-Accessibility-e1suib4","tags":["accessibility","Microsoft","inclusive design","AI/ML","inclusion"],"date_published":"2023-01-01T00:00:00Z"},{"id":"https://www.aaron-gustafson.com/publications/articles/welcoming-progressive-web-apps-to-microsoft-edge-and-windows-10/","title":"📄 Welcoming Progressive Web Apps to Microsoft Edge and Windows 10","content_html":"<p>Some of my Microsoft colleagues and I did a run-down of how we are supporting Progressive Web Apps in Windows.</p>\n","url":"https://blogs.windows.com/msedgedev/2018/02/06/welcoming-progressive-web-apps-edge-windows-10/","tags":["progressive web apps","Microsoft","browsers"],"date_published":"2018-02-06T00:00:00Z"},{"id":"https://www.aaron-gustafson.com/notebook/progressive-web-apps-and-the-windows-ecosystem/","title":"✍🏻 Progressive Web Apps and the Windows Ecosystem","summary":"I had the great pleasure of delivering this talk about Microsoft’s strategy towards Progressive Web Apps at the Build conference.","content_html":"<p><em>I had the great pleasure of delivering a talk about Microsoft’s strategy towards Progressive Web Apps at <a href=\"https://build.microsoft.com\">Build</a>. You can <a href=\"#slides\">view the slides</a> or <a href=\"#video\">watch the recording</a> of this talk, but what follows is a distillation of my talk, taken from my notes and slides.</em></p>\n<p>I’m here to talk to you about Progressive Web Apps, but before we really tuck into that, I wanna give a shout out to an app that’s really impressed me. This is Expense Manager by the folks at <a href=\"https://vaadin.com\">Vaadin</a>:</p>\n<figure class=\"video-embed video-embed--16x9\" id=\"figure-2017-05-24-01\">  \n<video class=\"video-embed__video\" src=\"/i/posts/2017-05-24/01.mp4\" controls loop muted></video>\n</figure>\n<p>I do a lot of traveling and it’s helpful when I can easily track my expenses. Their app is simple but refined in this regard. It’s snappy and provides a great overall UX; it’s also cross platform, which is nice since I often jump between different OSes across mobile and desktop.</p>\n<figure class=\"video-embed video-embed--16x9\" id=\"figure-2017-05-24-02\">  \n<video class=\"video-embed__video\" src=\"/i/posts/2017-05-24/02.mp4\" controls loop muted></video>\n</figure>\n<p>The experience on the desktop version of their app is obviously a little better because I’ve got more real estate for viewing my expenses, but the same attention to detail has clearly been paid to the experience in both form factors, which is nice to see.</p>\n<figure class=\"video-embed video-embed--16x9\" id=\"figure-2017-05-24-03\">  \n<video class=\"video-embed__video\" src=\"/i/posts/2017-05-24/03.mp4\" controls loop muted></video>\n</figure>\n<p>Oh, and a little secret here… it’s a web app. In fact it’s a Progressive Web App. You should really <a href=\"https://demo.vaadin.com/expense-manager\">play around with it yourself</a> and kick the tires a bit to see how it’s made.</p>\n<h2 id=\"what-is-a-progressive-web-app%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#what-is-a-progressive-web-app%3F\" aria-hidden=\"true\">#</a> What is a Progressive Web App?</h2>\n<p>Now that we’ve seen one in action, I want to start by clarifying what a Progressive Web App is, just so I’m sure we’re all on the same page before we go down this rabbit hole. As a point of clarification, you’ll hear me use the terms Progressive Web App and PWA interchangeably.</p>\n<p>So what is a Progressive Web App? Let’s ignore the first part of this term for a moment—<em>progressive</em>—I promise I’ll circle back to it shortly. Now the term “web app” may sound like something you can put your finger on, right? It’s software, on the Web, you use to complete a task. Like an expense manager, but it can be any website or property, really.</p>\n<p>And so it is with Progressive Web Apps too.</p>\n<figure id=\"fig-2017-05-24-04\" class=\"media-container\">\n<p><img src=\"https://www.aaron-gustafson.com/i/posts/2017-05-24/04.png\" alt=\"\"></p>\n</figure>\n<p>“Web apps” in this context can be any website type—a newspapers, games, books, shopping sites—it really doesn’t matter what the content or purpose of the website is, the “web app” moniker is applicable to all of them. <span data-quotable>The term could just have easily been progressive web <em>site</em> and it may be helpful to think of it as such</span>. It doesn’t need to be a single page app. You don’t need to be running everything client side. There are no particular requirements for the type of PWA you are developing.</p>\n<p>Essentially, a PWA is a website that is capable of being promoted to being an installed app. It gets many of the benefits of being an app (some of which I will cover shortly), but also has all of the benefits of being a website too. If you’ve looked at or developed a <a href=\"https://web.archive.org/web/20170616215532/https://developer.microsoft.com/en-us/windows/bridges/hosted-web-apps\">Hosted Web App</a>(HWA), which Microsoft introduced with Windows 10, PWAs are very\nsimilar. In fact, if you’ve built an HWA, it shouldn’t be too difficult for you to convert it into a PWA and, in doing so, you’ll get a ton of extra goodies for free… but I’m getting ahead of myself.</p>\n<p><a href=\"#figure-2017-05-24-05\">Here’s a quick comparison</a> of the Twitter app and <a href=\"https://lite.twitter.com/\">Twitter Lite</a>, as seen on an Android device:</p>\n<figure class=\"video-embed video-embed--16x9\" id=\"figure-2017-05-24-05\">  \n<video class=\"video-embed__video\" src=\"/i/posts/2017-05-24/05.mp4\" controls loop muted></video>\n<figcaption>A video showing the Twitter Android app and Twitter Lite, side-by-side to demonstrate how similar they are.</figcaption>\n</figure>\n<p>You’ll notice that from a quality, polish, and user experience perspective, they are nearly indistinguishable. And this is just the first iteration of Twitter Lite. It launched last month. The only real difference is that one was built using Web technologies and lives at a URL.</p>\n<p>Though <a href=\"https://infrequently.org/2015/06/progressive-apps-escaping-tabs-without-losing-our-soul/\">the “progressive web apps” moniker was coined by Frances Berriman in 2015</a> and has quickly become a buzzword in our industry, it’s important to recognize that this idea of the Web as app is not new.</p>\n<p>Back in 2007, <a href=\"https://web.archive.org/web/20070322155954/http://www.adobe.com/aboutadobe/pressroom/pressreleases/200703/031907ApolloLabs.html\">Adobe introduced Apollo</a>, later renamed the Adobe Integrated Runtime (<abbr aria-title=\"also known as\">a.k.a.</abbr> <a href=\"http://www.adobe.com/products/air.html\">Adobe AIR</a>). This technology enabled designers and developers to build apps in Flash or using Web technologies—HTML, CSS and JavaScript. It was pretty revolutionary for the time, supporting drag &amp; drop, menu bar integration, file management, and more.</p>\n<p>In 2009, Palm debuted <a href=\"https://en.wikipedia.org/wiki/WebOS\">webOS</a> <a href=\"http://www.palminfocenter.com/news/9668/palm-announces-the-palm-pre-smartphone/\">with the Palm Pre</a>. All software for webOS was built using web technologies. Sadly, as an operating system in the handset space, it failed to catch on, but <a href=\"https://www.lgwebos.com/\">LG has licensed webOS</a> for use in smart TVs and is experimenting with it for <abbr aria-title=\"Internet of Things\">IoT</abbr> devices and smartwatches.</p>\n<p>Since that time, more OSes have begun embracing Web technologies as a means of building applications. Windows 8 allowed Windows Store apps to be written in HTML, CSS, and JavaScript. And <a href=\"https://en.wikipedia.org/wiki/Firefox_OS\">Firefox OS</a> and <a href=\"https://www.chromium.org/chromium-os\">Chromium/Chrome OS</a> are fundamentally tied to to the Web stack.</p>\n<p>Countless tools have followed Adobe’s lead as well, enabling designers and developers to use their Web skills to build applications for the vast majority of operating systems out there. <a href=\"https://facebook.github.io/react-native/\">React Native</a>, <a href=\"http://ionicframework.com/\">Ionic</a>, <a href=\"https://electron.atom.io/\">Electron</a>, <a href=\"http://phonegap.com/\">PhoneGap</a>, <a href=\"http://www.appcelerator.com/\">Appcelerator</a>… the list goes on and on. Obviously there’s something to the idea of building software using Web technologies. Progressive Web Apps are a brilliant way of accomplishing this in a standardized, consistent, way.</p>\n<h2 id=\"what-makes-a-pwa-a-pwa%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#what-makes-a-pwa-a-pwa%3F\" aria-hidden=\"true\">#</a> What makes a PWA a PWA?</h2>\n<p>Google’s <a href=\"https://infrequently.org/\">Alex Russell</a> defined 10 characteristics he believes define this new breed of Web application:</p>\n<ol>\n<li><strong>Progressive:</strong> It works for every user, regardless of browser choice because it’s built with progressive enhancement as a core tenet.</li>\n<li><strong>Responsive:</strong> The UI adapts to fit any form factor.</li>\n<li><strong>Network independent:</strong> It works offline and on low-quality networks (which is something <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker\">Service Worker</a> helps with).</li>\n<li><strong>App-like:</strong> It feels like an app in terms of responsiveness and UX.</li>\n<li><strong>Fresh:</strong> The experience is always up to date (another area where Service Worker shines).</li>\n<li><strong>Safe:</strong> It is served via HTTPS to prevent snooping and to ensure content hasn’t been tampered with.</li>\n<li><strong>Discoverable:</strong> Search spiders can identify it as an app because it uses a <a href=\"https://developer.mozilla.org/en-US/docs/Web/Manifest\">Web Application Manifest</a> (and a Service Worker).</li>\n<li><strong>Re-engageable:</strong> It can re-engage users through features like <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Push_API\">push notifications</a>.</li>\n<li><strong>Installable:</strong> It can be installed by users if they find it useful. This could be done independently of—but is not necessarily exclusive of—app stores.</li>\n<li><strong>Linkable:</strong> It is easily accessed (and shared) via a URL.</li>\n</ol>\n<p>Let’s tuck into the installable piece first since this is the bit that really sets a PWA apart from a standard website. Now many might view this as a continuation of the competition between Web and traditional app development. I don’t think of the two as being competitive, so much as being choices. We should choose our development approach based on the needs of our project, team, budget, etc. It’s good to have options and both approaches have their strengths.</p>\n<blockquote>\n<p><del>Web vs. Platform-specific</del><br>\n<ins>Web *or* Platform-specific?<br>\nIt depends.</ins></p>\n</blockquote>\n<p>Often Web tech gets dismissed for not having the capabilities of apps. That’s changing rather rapidly. A visit to <a href=\"https://whatwebcando.today/\">whatwebcando.today</a> will give you a run-down of what your browser supports; you might be surprised with what you’ll learn about your browser’s capabilities. And if the end user experience is really good, does it matter what the underlying technology is?</p>\n<p>Well, it might…</p>\n<p>In the Web vs. apps discussion, time to market is an aspect that isn’t often discussed. With a traditional web and app approach, each platform is typically built atop a core API. The apps are designed and developed independently, using different toolsets and languages and requiring different skills from the development team. And even in instances where they are all created using a single tool, the timeline needs to be padded in order to account for submission to each app store. That can cause delays in getting your product in front of users. It can also delay your delivery of critical updates.</p>\n<figure id=\"fig-2017-05-24-06\" class=\"media-container\">\n<p><img src=\"https://www.aaron-gustafson.com/i/posts/2017-05-24/06.png\" alt=\"\"></p>\n</figure>\n<p>Contrast that with building your software as a web-based product with the characteristics of a PWA. Using this approach, you can build it once and deploy it everywhere… <em><a href=\"https://cloudfour.com/thinks/progressive-web-apps-simply-make-sense/\">even to platforms that don’t support PWAs</a>!</em> And if you opt to submit your app to the various app stores, you could likely get away with a a one-time submission because updates will be seamless from there on out—it is the Web after all.</p>\n<figure id=\"fig-2017-05-24-07\" class=\"media-container\">\n<p><img src=\"https://www.aaron-gustafson.com/i/posts/2017-05-24/07.png\" alt=\"\"></p>\n</figure>\n<p>Now that we’ve talked about install ability—the “app” bit, if you will—let’s circle back to that first principle of Progressive Web Apps: <em>progressive</em>. It must be important, after all it is literally the first word in this approach. “Progressive” in this context refers to <em>progressive enhancement</em>. In case you’re unfamiliar with the idea, I’ll provide a quick analogy; I’m a huge music and movie fan, so we’ll focus on sound for this analogy.</p>\n<p>Back in the early days of recording, we only had a single speaker (or horn, back in the Victrola days) to relay the sound to our ears. Round about the 1930s, modern two-channel stereophonic sound was invented to solve a cinematic problem: in early “talkies” a single channel of sound was delivered through multiple speakers, which sometimes led to a weird situation where a performer would be on one side of the screen, but their voice would be coming from the other side (the speaker near you). Stereo sound allowed the actor’s voice to follow them in a much more natural way. Even with this advancement, though, stereo recordings could still be listened to on a single speaker by combining the channels.</p>\n<p>Over time, stereophonic sound gave way to quadrophonic (or “surround”) sound and we kept adding more channels… and more channels, creating more and more immersive experiences. But even though a recording might sound best in 16.2 or 22.2<sup class=\"footnote-ref\"><a href=\"#fn1\" id=\"fnref1\">1</a></sup> channels of sound, movies, television, and music mastered for complete immersion can still be appreciated on a single, mono bluetooth speaker or on your mobile device (which is basically in mono when you’re viewing it in landscape mode). That is progressive enhancement.</p>\n<figure class=\"video-embed video-embed--16x9\" id=\"figure-2017-05-24-08\">  \n<video class=\"video-embed__video\" src=\"/i/posts/2017-05-24/08.mp4\" controls loop muted></video>\n<figcaption>An animated explanation of progressive enhancement using sound channels.</figcaption>\n</figure>\n<p>Progressive enhancement is concerned with honoring the core purpose of an experience—in software’s case the core purpose of a project and the core tasks a user will want to accomplish using it. The core experience should always be available, regardless of device or browser being used or the capabilities or limitations of that device… or of the user. It doesn’t mean you can’t create a better experience for folks who can benefit from that, but you never do that to the exclusion of your users.</p>\n<p>And yes, that means having an experience that works when JavaScript doesn’t. But that’s a whole other talk…</p>\n<p>With progressive enhancement, we build the baseline experience and then enhance it as we are able to. In practical terms, progressive enhancement ensures people can use your product, regardless of</p>\n<ul>\n<li>Unsupported browser and/or device features Network issues that block or delay important assets,</li>\n<li>Browser plug-ins that interfere with JavaScript execution,</li>\n<li>3rd party code that interferes with JavaScript execution.</li>\n<li>Proxy browsers that optimize/adjust your code,</li>\n<li>Your users requiring alternate input methods or assistive tech,</li>\n<li>etc.</li>\n</ul>\n<figure id=\"fig-2017-05-24-09\" class=\"media-container\">\n<p><img src=\"https://www.aaron-gustafson.com/i/posts/2017-05-24/09.png\" alt=\"\"></p>\n<figcaption>A chart plotting capabilities against experience, showing a steady improvement in experience as the number of capabilities increase.</figcaption>\n</figure>\n<p>Let me walk you through a very basic example of progressive enhancement in practice as I think it will illustrate this point.</p>\n<p>Here we have an email input field:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>input</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>email<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">required</span> <span class=\"token attr-name\">aria-required</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>true<span class=\"token punctuation\">\"</span></span> <span class=\"token punctuation\">/></span></span></code></pre>\n<p>The “email” field type was introduced in HTML5, so older browsers may not support it. Those that don’t will provide the default <code>input</code> type—a text field—to users. That’s totally fine—it’s all we had for more than a dozen years before HTML5 came along! But even if a user’s device does support email fields, it’s implementation may vary. Based on how a browser answers the following questions, users will end up with different experiences:</p>\n<ul>\n<li>Do you support for email input type?</li>\n<li>Do you support the HTML5 form validation algorithm including the email format?</li>\n<li>Do you offer a virtual keyboard?</li>\n</ul>\n<p>Moving on to the <code>required</code> attribute—another HTML5 introduction—some browsers will use it for input validation, some won’t know what to do with it. Those that implement this feature may block form submission if the field is left empty, but some won’t do anything with that info <em>even if they know the field is empty</em>!</p>\n<p>Finally, there’s the <code>aria-required</code> attribute. This is a part of the ARIA (Accessible Rich Internet Applications) spec and is used to inform assistive technology if the field is required. But it’s possible the browser may not support the attribute or that the assistive tech being used may not do anything with that information even if the browser does expose it.</p>\n<p>In terms of experience of this field, it improves incrementally along a path like this:</p>\n<ol>\n<li>Input…</li>\n<li>with required notification to assistive tech…</li>\n<li>with required enforcement…</li>\n<li>with email type validation…</li>\n<li>with speedier entry via virtual keyboard.</li>\n</ol>\n<figure id=\"fig-2017-05-24-10\" class=\"media-container\">\n<p><img src=\"https://www.aaron-gustafson.com/i/posts/2017-05-24/10.png\" alt=\"\"></p>\n</figure>\n<p>Now think about that for a second—this incredible variety of experience is created by one HTML element when you add three specific attributes to it. And the experienced is enhanced—<em>progressively</em>—as the browser’s and operating system’s capabilities increase. Amazing!</p>\n<p>As I mentioned, <span data-quotable>progressive enhancement ensures people can use your product, no matter what</span>. You could just as easily swap in “PWA” for “progressive enhancement” in that statement. After all, PWAs give you network awareness and independence, they can be used to lower the overall cost of using your product for your for users through smart caching, they enable access to platform APIs on certain platforms, and they provide more ways for your product to get discovered (e.g., search, store, links). Those are some impressive progressive enhancement bona fides.</p>\n<p>Additionally, the two technical lynchpins of PWA—Web App Manifest and Service Worker—are ignored if they aren’t supported. Products you build using them <a href=\"https://cloudfour.com/thinks/why-does-the-washington-posts-progressive-web-app-increase-engagement-on-ios/\">will continue to work really well, even in their absence</a>. They are, by definition, progressive enhancements too.</p>\n<p>Now I’ve mentioned Service Worker a few times, so it probably makes sense to do a little sidebar here to explain what Service Workers are. A Service Worker is a proxy spawned by JavaScript that can handle a variety of tasks involving the network. They can</p>\n<ul>\n<li>Manage offline experiences,</li>\n<li>Intercept and respond to or modify network requests,</li>\n<li>Manage caching,</li>\n<li>Receive and handle push notifications, and</li>\n<li>Handle background sync requests.</li>\n</ul>\n<p><em>Note: At this point in the presentation, I passed the mic to my colleague <a href=\"https://twitter.com/boyofgreen\">Jeff Burtoft</a> to give a quick demo of Service Worker in practice.</em></p>\n<h2 id=\"what%E2%80%99s-the-timeline-for-progressive-web-apps-in-windows%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#what%E2%80%99s-the-timeline-for-progressive-web-apps-in-windows%3F\" aria-hidden=\"true\">#</a> What’s the timeline for Progressive Web Apps in Windows?</h2>\n<p>Now that we’ve covered the groundwork of PWAs, I want to discuss where they fit in the Windows ecosystem. As I mentioned earlier, Windows has a history of supporting Web tech, but it even predates Windows 8. Back in Windows 7 we began supporting <a href=\"https://msdn.microsoft.com/en-us/library/gg491738(v=vs.85).aspx\">pinned sites</a>. They enabled developers to customize a sticky tab in the taskbar that provided quick access to key tasks, a customizable browser UI, and more. Then, in Windows 8, packaged apps could be completely written in HTML, CSS, and JavaScript. In Windows 10 we introduced Hosted Web Apps, which enabled your wholly web-based product to be distributed and installed via the Windows Store. And now we are in the process of taking our support of the Web to the next level with Progressive Web Apps.</p>\n<p>In terms of the work necessary to make this happen, the Edge team has already landed <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\">Fetch API</a> support. Fetch is the powerful successor to <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest\">XMLHttpRequest</a> that is a critical underpinning of Service Worker. As I mentioned, Hosted Web Apps arrived with Windows 10 and they provide a secure, discrete container for Web apps within Windows that will also be used with PWAs. Additionally, <a href=\"https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/winrt-from-js\">WinRT</a> provides programmatic access to OS internals like the calendar, contacts, Cortana, and more via JavaScript.</p>\n<p>Our engineering effort around Service Worker kicked off about a year ago and we’re making great progress in bringing PWAs to Edge and Windows. Support for PWAs will become available to Windows Insiders early this summer. Initially, Service Worker, the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Cache\">Cache API</a>, and the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Push_API\">Push API</a> will be behind a <a href=\"http://www.windowscentral.com/understanding-aboutflags-microsoft-edge\">feature flag</a>.</p>\n<p>Once PWAs are fully supported, they will use the same container technology currently in use for Hosted Web Apps. As I mentioned, it’s an established container with excellent performance and a ton of benefits:</p>\n<ul>\n<li>Standalone Window</li>\n<li>Independent from browser process\n<ul>\n<li>Less overhead</li>\n<li>Isolated cache</li>\n<li>Nearly unlimited storage (indexed DB, localStorage, etc.)</li>\n</ul>\n</li>\n<li>Offline &amp; background processes</li>\n<li>Access to Windows Runtime (WinRT) APIs via JavaScript\n<ul>\n<li>Calendar</li>\n<li>Cortana</li>\n<li>Address Book</li>\n</ul>\n</li>\n</ul>\n<p>On Windows, Progressive Web Apps are essentially Hosted Web Apps, evolved. In fact, you could build your PWA and ship it as an HWA today and when the remainder of the PWA stack lands, it will automatically transform into a full-fledged PWA (another benefit of the Web for distribution).</p>\n<h2 id=\"how-does-a-user-discover-a-progressive-web-app%3F\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#how-does-a-user-discover-a-progressive-web-app%3F\" aria-hidden=\"true\">#</a> How does a user discover a Progressive Web App?</h2>\n<p>Now that we’ve seen how PWAs operate within Windows, I want to take a few minutes to talk about how users will find your PWAs. As part of our initial move to support Progressive Web Apps, we will be enabling users to discover and install them from within the store and in Bing search results.</p>\n<figure id=\"fig-2017-05-24-11\" class=\"media-container\">\n<p><img src=\"https://www.aaron-gustafson.com/i/posts/2017-05-24/11.jpg\" alt=\"\"></p>\n<figcaption>Screenshots of Bing search results and the Windows Store, highlighting how an app might appear in both contexts.</figcaption>\n</figure>\n<p>Now you may be wondering, with all of the awesomeness the Web has to offer, why does it make sense for PWAs to reside in app stores? There are numerous reasons:</p>\n<ol>\n<li>It puts PWAs on equal footing with traditional apps.</li>\n<li>Stores provide an alternate means of discovery for PWAs.</li>\n<li>Users are generally more comfortable trusting software that has been reviewed for quality and safety.</li>\n<li>Developers can get more insight into their users through reviews and ratings as well as analytics concerning installs, uninstalls, shares, and performance.</li>\n<li>Having a store where users download software also reduces the cognitive overhead of tracking multiple sources for installing apps.</li>\n</ol>\n<p>PWAs can get into the Windows Store in one of two ways. The first is through active submission. Using a tool like the open source utility <a href=\"http://www.pwabuilder.com/\">PWA Builder</a>, you can generate the necessary app wrappers used by the various app stores and manually submit your PWA.</p>\n<p><em>Note: I invited Jeff back up on stage to walk through building a PWA and submitting it to the Windows Store using PWA Builder.</em></p>\n<p>Obviously we want Windows users to have access to as many quality PWAs as possible, but we recognize that not all development teams have the time to submit and maintain their apps in the Store. To address this, we’ve developed an approach to enable their apps to be easily discovered in the Store too. For lack of a better term, we’re currently calling this process “passive ingestion”.</p>\n<figure id=\"fig-2017-05-24-12\" class=\"media-container\">\n<p><img src=\"https://www.aaron-gustafson.com/i/posts/2017-05-24/12.png\" alt=\"\"></p>\n</figure>\n<p>We are already using the Bing Crawler to identify PWAs on the Web for our PWA research. The Web App Manifest is a proactive signal from developers that a given website should be considered an app; we’re listening to that signal and evaluating those sites as candidates for the Store. Once we identify quality PWAs, we’ll automatically generate the APPX wrapper format used by the Windows Store and assemble a Store entry based on metadata about the app provided in the Web App Manifest.</p>\n<p>We completely understand that some of you may not want your products automatically added to the Store and we respect that.\nBy adding these 2 lines to your site’s <a href=\"http://www.robotstxt.org/robotstxt.html\"><code>robots.txt</code> file</a>, the Bing Crawler will ignore your Web App Manifest, opting your site out of this process:</p>\n<pre class=\"language-txt\" tabindex=\"0\"><code class=\"language-txt\">User-agent: bingbot\nDisallow: /manifest.json</code></pre>\n<p>We are working on a set of criteria that will help us separate quality PWAs from sites that simply appear PWA-like. It’s still early days, but our consideration of what constitutes a “quality” PWA hinges on the following:</p>\n<ul>\n<li><strong>Does this site have a Web App Manifest?</strong> In our initial crawl of sites looking for PWAs, we discovered over 1.5 million manifests across 800k domains. Looking at a selection of these sites, we discovered that not all are good candidates for ingestion. Some aren’t PWAs at all, others have a boilerplate manifest generated by tools like favicon generators.</li>\n<li><strong>Does the Web App Manifest suggest quality?</strong> We will be looking for non-boilerplate manifests that include a name, description, and at least one icon that is larger than 192px square.</li>\n<li><strong>Is the site secure?</strong> At this point, we are only looking for HTTPS, we aren’t evaluating <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP\">CSP</a> or other protections.</li>\n<li><strong>Does the site have a valid Service Worker?</strong> <a href=\"https://serviceworke.rs/\">Mozilla has a bunch of recipes</a> if you are looking for somewhere to start.</li>\n<li><strong>Is the site popular?</strong> We will prioritize sites that rank highly on <a href=\"http://www.alexa.com/topsites\">Alexa</a>, <a href=\"https://www.quantcast.com/top-sites\">Quantcast</a>, and other “top sites” lists.</li>\n<li><strong>Does the site pass automated testing for quality?</strong> There are a number of tools out there for this, including our <a href=\"https://developer.microsoft.com/en-us/microsoft-edge/tools/staticscan/\">Site Scanner</a>, <a href=\"https://developers.google.com/web/tools/lighthouse/\">Lighthouse</a>, <a href=\"https://www.deque.com/products/axe/\">aXe</a>, and more.</li>\n<li><strong>Is the app content free?</strong> There are certainly ways to charge for apps and content in the Windows Store, but we won’t passively ingest any sites that require a licensing fee or subscription. You’ll be able to submit those manually though.</li>\n<li><strong>Does the app pass manual review?</strong> PWAs will need to meet the standards of the Windows Store, just like any other app. We will not ingest apps that violate laws or Store policies.</li>\n</ul>\n<p>Once in the Store, we’ll notify developers of their draft Store entry and they will be able to claim their apps to take complete control of their Store presence. Regardless, whether they got their by passive ingestion or my manual submission, the Web App Manifest will provide the basic set of information used for the app in the Store: name, description, icons, and screenshots. We’re also actively working with others in the W3C to introduce support for <a href=\"https://github.com/w3c/manifest/issues/569\">app categories</a> and <a href=\"https://github.com/w3c/manifest/issues/523\">IARC ratings</a>.</p>\n<p>PWAs will appear alongside other apps in the Store, with no differentiation. From a users’ perspective, a PWA will just be another app. They will install just like any other app. They will have settings just like any other app. They will uninstall just like any other app. They will also be shareable via URL or the Store. PWAs will be first-class apps on Windows.</p>\n<hr>\n<p>Phew… that was a lot to take in. At this point, you might have some questions. Here are a few I imagine you’re wrestling with.</p>\n<p><strong>Should I forget everything I know and start building a Progressive Web App?</strong></p>\n<p><em>No.</em> Progressive Web Apps are just one more way you can build a high-quality app experience.</p>\n<p><strong>Will Microsoft drop support for my favorite programming language in favor of Progressive Web Apps?</strong></p>\n<p><em>No.</em> We are committed to supporting a breadth of language options when it comes to developing apps.</p>\n<p><strong>Are Progressive Web Apps the right choice for my project?</strong></p>\n<p><em>Maybe.</em> When evaluating app development in relation to Progressive Web Apps, here are some of the questions I recommend asking…</p>\n<ul>\n<li>Are there features the Web can’t offer that are critical to the success of this product?</li>\n<li>What is the total cost (time and money) of building and maintaining each platform-specific app?</li>\n<li>What are the strengths of my dev team? <em>or</em> How easy will it be to assemble a new team with the necessary skills to build each app as opposed to a PWA?</li>\n<li>How critical will immediate app updates (e.g., adding new security features) be?</li>\n</ul>\n<p>In other words, the choice between PWA and a platform-specific app should be evaluated on a case-by-case basis. For example…</p>\n<ul>\n<li>If you are looking to craft an experience that takes full advantage of each platform you release it on and you want to agonize over every UX detail in order to differentiate your product… an app <em>might</em> be the best choice for you.</li>\n<li>If you are maintaining a product on multiple platforms in addition to the Web and they are all largely the same in terms of look &amp; feel and capabilities, it may make more sense to focus all of your efforts on the Web version and go PWA.</li>\n<li>If you are planning a brand new product and the Web provides all of the features you need (especially when you also consider the additional APIs provided via the host OS), building a PWA is probably going to be a faster, more cost-effective option.</li>\n</ul>\n<p><strong>Should I consider Progressive Web Apps as a solid option when developing software for Windows?</strong></p>\n<p><em>Definitely.</em></p>\n<p>You probably have more questions. I’ll do my best to answer them in the comments.</p>\n<h2 id=\"slides\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#slides\" aria-hidden=\"true\">#</a> Slides</h2>\n<p><a href=\"https://www.slideshare.net/AaronGustafson/progressive-web-apps-and-the-windows-ecosystem-build-2017\">Slides from this talk</a> are available on <a href=\"https://www.slideshare.net\">Slideshare</a>.</p>\n<figure class=\"video-embed video-embed--16x9\" id=\"figure-2017-05-24-13\">  \n<iframe class=\"video-embed__video\" src=\"https://www.slideshare.net/slideshow/embed_code/key/InI5w0bH4JxCwW\" frameborder=\"0\"></iframe>\n</figure>\n<h2 id=\"video\" tabindex=\"-1\"><a class=\"header-anchor\" href=\"#video\" aria-hidden=\"true\">#</a> Video</h2>\n<p><a href=\"https://channel9.msdn.com/Events/Build/2017/B8075\">A video recording of this presentation</a> (including Jeff’s demos) is available on <a href=\"https://channel9.msdn.com\">Channel 9</a>.</p>\n<figure class=\"video-embed video-embed--16x9\" id=\"figure-2017-05-24-14\">  \n<iframe src=\"https://channel9.msdn.com/Events/Build/2017/B8075/player\" width=\"900\" height=\"540\" allowFullScreen frameBorder=\"0\"></iframe>\n</figure>\n<p><em>Note: I no longer use “native” in the context of apps and platforms, but it remains in quoted material.</em></p>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<h4 class=\"hidden\">Footnotes</h4>\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>Crazy as it sounds, 22.2 is actually the standard used by Ultra-High Definition (UHD) television. <a href=\"#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n","url":"https://www.aaron-gustafson.com/notebook/progressive-web-apps-and-the-windows-ecosystem/","tags":["progressive web apps","progressive enhancement","Windows","Microsoft","presentations"],"date_published":"2017-05-24T15:13:24Z"},{"id":"https://www.aaron-gustafson.com/speaking-engagements/progressive-web-apps-and-the-windows-ecosystem/","title":"📢 Progressive Web Apps and the Windows Ecosystem","summary":"In this session, I discuss what PWAs are, how they can be integrated into the development process of modern websites, the advantages and disadvantages of PWAs vs. native development, and what opportunities they present when installed alongside native apps in Windows.","content_html":"<p>Whether at home or at work, the web plays an increasingly critical role in our daily lives. As we have become more dependent on accessing the tools it powers, we’ve also struggled to overcome some of its limitations—network connectivity, for instance.</p>\n<p>At Microsoft, we’ve long been interested in the power of the web for software development and we are even more excited for the future possibilities offered by progressive web apps (PWAs). In this session, I discuss what PWAs are, how they can be integrated into the development process of modern websites, the advantages and disadvantages of PWAs vs. native development, and what opportunities they present when installed alongside native apps in Windows.</p>\n","social_text":"In this session, I discuss what PWAs are, how they can be integrated into the development process of modern websites, the advantages and disadvantages of PWAs vs. native development, and what opportunities they present when installed alongside native apps in Windows.","url":"https://www.aaron-gustafson.com/speaking-engagements/progressive-web-apps-and-the-windows-ecosystem/","tags":["progressive web apps","progressive enhancement","Windows","Microsoft"],"image":"https://www.aaron-gustafson.com/undefined","date_published":"2017-05-10T13:00:00Z"},{"id":"https://www.aaron-gustafson.com/notebook/what-would-you-do-with-10kb/","title":"✍🏻 What Would You Do With 10kB?","summary":"I’m thrilled to announce that the 10k Apart contest is back and brings with it a handful of new challenges.","content_html":"<p>Sixteen years ago, <a href=\"https://twitter.com/stewart\">Stewart Butterfield</a> conceived of a contest that would test the mettle of any web designer: <a href=\"http://web.archive.org/web/20000510010054/http:/www.sylloge.com/5k/home.html\">The 5k</a>. The idea was that entrants would build <a href=\"http://alistapart.com/article/5k\">an entire site in 5kB of code or less</a>. Its aim was to force us to get creative by putting a bounding box on what we could do:</p>\n<blockquote>\n<p>Between servers and bandwidth, clients and users, HTML and the DOM, browsers and platforms, our conscience and our ego, we’re left in a very small space to find highly optimal solutions. Since the space we have to explore is so small, we have to look harder, get more creative; and that’s what makes it all interesting.</p>\n</blockquote>\n<p>The 5k contest ran from 2000 until 2002. In 2010, <a href=\"http://www.zeldman.com/2010/07/29/10k-apart-%E2%80%93%C2%A0inspire-the-web/\">An Event Apart and Microsoft revived the idea</a> with an updated limit and a new name: <a href=\"http://web.archive.org/web/20100730090946/http:/10k.aneventapart.com/\">10k Apart</a>. Staying true to its roots, this new incarnation, which ran for two years, continued to push designers and developers to get creative within a pretty extreme (though slightly expanded) limit while incorporating new goodies like HTML5 and responsive design.</p>\n<p>I’m thrilled to announce that <a href=\"https://a-k-apart.com/\">the 10k Apart contest is back</a> and brings with it a handful of new challenges:</p>\n<ol>\n<li><strong>Each page must be usable in 10kB or less.</strong> The 10kB limit no longer applies to the size of a ZIP archive of your entry; the 10kB limit now applies to the total initial download size of the baseline experience of each page in your project. When we say “baseline experience,” we’re talking small screen devices running older, less capable browsers. The 10kB limit will apply to every page and whatever assets it loads by default; that means images, CSS, JavaScript, and so on.</li>\n<li><strong>Progressive enhancement is the name of the game.</strong> Your project should start with a super-basic, bare-bones-but-usable experience that will work no matter what (including without JavaScript). You can use clever CSS and JavaScript techniques to enhance that experience as it makes sense to do so. For example: You might lazy load an image using JavaScript if the screen size is above a certain threshold or when certain other conditions are met. Entries that depend entirely on JavaScript to render the front-end won’t be accepted. If you need a primer on progressive enhancement, <a href=\"https://alistapart.com/?s=progressive+enhancement\">consult the pages of <cite>A List Apart</cite></a>.</li>\n<li><strong>Back ends are in this year.</strong> In previous iterations, each entry comprised client-side code submitted via ZIP file. Over time, that limitation led to an over-reliance on JavaScript for rendering. No more. This year, you can create dynamic experiences that work without front-end JavaScript using Node, PHP, Python or .Net. You will submit your entry as public GitHub repository (so we can all learn from your awesome code) and we’ll spin up a dedicated <a href=\"https://azure.microsoft.com/\">Azure</a> instance running the appropriate stack.</li>\n<li><strong>Entries should be accessible.</strong> In line with the philosophy of progressive enhancement, your entry should be usable by the broadest number of users possible. <a href=\"https://web.archive.org/web/20121026082353/http://www.accessiq.org/news/commentary/2012/09/web-accessibility-is-a-mindset-not-a-checklist\">Accessibility is not a checklist</a>, but if you’re clueless about where to start, <a href=\"https://www.w3.org/TR/WCAG20-TECHS/\">these techniques</a> can offer some guidance.</li>\n<li><strong>Nothing comes for free.</strong> In previous years, we gave a pass if you wanted to use jQuery or load some fonts from Typekit. This year we decided to change it up, not because we don’t love these products (we do), but because we wanted to force every piece of code, every asset, to fight for its place in your entry. Anything you add should be added with purpose.</li>\n</ol>\n<p>As with previous editions, your entry should use web standards and work in all modern browsers. You can use HTML, CSS, and JavaScript features and APIs that don’t have across-the-board support as long as you do so in keeping with the progressive enhancement philosophy. In other words, your entry can’t depend on that technology or feature in order to be usable.</p>\n<p>All of this may sound like a tall order, but it’s entirely possible. In fact, the site we built for the contest also abides by these rules. My colleagues and I will touch on some of the techniques we used (and concessions we made) in building the site in future posts.</p>\n<p>If you’ve read this far, you might be wondering <em>What’s in it for me?</em> Well, bragging rights, of course, but we’ve got some awesome prizes too! We’re giving away $10,000 to the top three entries, plus <a href=\"http://aneventapart.com/events\">tickets to An Event Apart</a>, complete collections of <a href=\"https://abookapart.com/collections/standards-collection\">A Book Apart titles</a>, and copies of <a href=\"http://adaptivewebdesign.info/2nd-edition/\">my book</a> too. <a href=\"https://a-k-apart.com/#prizes\">Complete details of the prizes</a> are over on <a href=\"https://a-k-apart.com/\">the contest site</a>.</p>\n<p>We’ve lined up an amazing group to judge the entires this year too: <a href=\"https://twitter.com/rachelandrew\">Rachel Andrew</a>, <a href=\"https://twitter.com/lara_hogan\">Lara Hogan</a>, <a href=\"https://twitter.com/wilto\">Mat Marquis</a>, <a href=\"https://twitter.com/Heydonworks\">Heydon Pickering</a>, <a href=\"https://twitter.com/jensimmons\">Jen Simmons</a>, and <a href=\"https://twitter.com/SaraSoueidan\">Sara Soueidan</a> will all be putting your entry through its paces and peering under the hood at your code. There’s also a People’s Choice award which will be based on votes you cast. Voting will open October 1st and run through October 14th.</p>\n<p>The contest opened Monday and we will accept entries until 5pm Pacific Time on September 30th. <a href=\"https://a-k-apart.com/legal\">Everything you should need to know about the contest, eligibility, etc.</a> is up on <a href=\"https://a-k-apart.com/\">the 10k Apart site</a>, but if you have additional questions, <a href=\"https://a-k-apart.com/hi\">you can always reach out</a>.</p>\n<p>I can’t wait to see what you come up with! Happy coding!</p>\n","url":"https://www.aaron-gustafson.com/notebook/what-would-you-do-with-10kb/","tags":["web design","accessibility","Microsoft","performance","progressive enhancement"],"date_published":"2016-08-17T18:48:27Z"},{"id":"https://www.aaron-gustafson.com/notebook/collected-reactions-to-build/","title":"✍🏻 Collected Reactions to //build/","summary":"I may work for Microsoft, but I don’t know everything that’s going on across the company. It’s big and I don’t have that kind of time.","content_html":"<p>I may work for Microsoft, but I don’t know everything that’s going on across the company. It’s big and I don’t have that kind of time.</p>\n<p>Anyway <a href=\"http://aka.ms/ktlsyd\">Build</a>, the Microsoft conference, is going on right now and as you’d expect, there are a ton of new announcements. I’ve watched a few of the talks virtualy and am particularly excited about the new browser (whose name has finally been revealed): <a href=\"https://www.microsoft.com/en-us/windows/browser-for-doing\">Microsoft Edge</a>. I’m also very interested to see where things go with <a href=\"https://www.microsoft.com/microsoft-hololens/en-us\">HoloLens</a>.</p>\n<p>One graphic that cropped up that blew my mind was this one talking about where Windows 10 is going:</p>\n<figure id=\"fig-2015-04-30-01\" class=\"media-container\">\n<p><img src=\"https://news.microsoft.com/build2015/assets/photos/build720150428_web.png\" alt=\"The Windows 10 continuum from an Internet of Things board up to a SurfaceHub and HoloLens\"></p>\n</figure>\n<p>You’ve often heard me discuss <a href=\"http://adaptivewebdesign.info/1st-edition/read/chapter-1.html\">experience as a continuum</a>. Microsoft is living it.</p>\n<p>If you didn’t watch the streaming talks and want to hear about what was announced from some independent sources, I’d recommend reading these:</p>\n<ul>\n<li><a href=\"http://www.wired.com/2015/04/microsoft-build-hololens/\">Microsoft Shows HoloLens’ Augmented Reality Is No Gimmick</a> — <cite>Wired</cite>\nA good overview of the possibilities of HoloLens with a recap of what was shown. I caught this demo on the lifestream. It was pretty impressive. I can’t wait to try a HoloLens myself.</li>\n<li><a href=\"http://thenextweb.com/microsoft/2015/04/30/microsoft-opens-up-applications-for-developers-to-test-ios-and-android-app-conversion-tools/\">Microsoft opens up applications for developers to test iOS and Android app conversion tools</a> — <cite>The Next Web</cite>\nThe Microsoft App Store is a little scant on first-rate programs right now, so in a play to make it stupid-simple for iOS and Android developers to run on Windows 10, the folks at Microsoft have built a conversion tool that ports the app for you. It’s worth noting that you can also port a website into a Windows app. Smart move on Microsoft’s part if you ask me.</li>\n<li><a href=\"http://thenextweb.com/microsoft/2015/04/30/hands-on-with-the-new-minimalist-microsoft-edge-browser/\">Hands-on: The new Microsoft Edge browser is a picture of minimalism</a> — <cite>The Next Web</cite>\nObviously the web is where I live and work. I’ve been playing with early builds of the new Microsoft browser for a few months now and have been pretty happy with its speed and capabilities, but it is nice to read an outside perspective on it.</li>\n<li><a href=\"http://gizmodo.com/microsoft-just-nonchalantly-showed-us-the-single-device-1701020050\">Microsoft Just Nonchalantly Showed Us the Single-Device UI of the Future</a>\nI don’t know about “nonchalantly”, but the whole Continuum feature is pretty amazing. The potential for being able to use the computer in your pocket with other peripherals is pretty intriguing. Imagine using your phone, a set of holographic or <a href=\"http://www.amazon.com/Cinemizer-1909-127-Multimedia-Video-Glasses/dp/B0091OI530/\">virtual screen glasses</a>, and a bluetooth keyboard &amp; mouse to get work done on a plane. No need to worry about someone leaning back and breaking your laptop!</li>\n<li><a href=\"http://techcrunch.com/2015/04/30/hololens-is-real/\">HoloLens Hands-On: How We Built An App For Microsoft’s Augmented Reality Headset</a><br>\nOne reporter’s experience developing for and playing with HoloLens. Sounds like it was pretty cool. I wonder if it can be tweaked to work for people with poor vision like me or if it fits nicely over glasses.</li>\n<li><a href=\"http://www.wired.com/2015/05/microsofts-one-billion-device-vision-genius-next-impossible/\">Microsoft’s Windows 10 Vision Isn’t As Simple as It Seems</a><br>\nA deeper analysis of Microsoft’s play for more developer (and consumer) mindshare.</li>\n</ul>\n<p><em>I will continue adding to this list as new &amp; interesting pieces come out</em>.</p>\n","url":"https://www.aaron-gustafson.com/notebook/collected-reactions-to-build/","tags":["Microsoft","web design","Android"],"date_published":"2015-04-30T14:53:11Z"},{"id":"https://www.aaron-gustafson.com/notebook/talking-with-microsoft-about-ienext/","title":"✍🏻 Talking with Microsoft about IE.next","summary":"You may recall that the DOM Scripting and Microsoft task forces, in collaboration with JS Ninjas, had been compiling a list of issues, needs, and wants for IE .next over the last few months (a list many of you contributed to as well…","content_html":"<p>You may recall that the DOM Scripting and Microsoft task forces, in collaboration with <abbr title=\"JavaScript\">JS</abbr> Ninjas, had been <a href=\"http://www.webstandards.org/2006/11/04/you-can-improve-ie-next/\">compiling a list of issues, needs, and wants for <abbr title=\"Internet Explorer\">IE</abbr>.next</a> over the last few months (a list many of you contributed to as well, via your feedback). The list was to focus on what we wanted to see happen in terms of JavaScript support (as <abbr title=\"Internet Explorer 7\">IE7</abbr> didn’t get much of an update in that area), but when it came down to it, there were other areas we really felt needed some love.</p>\n<h3>The list</h3>\n<p>Last week, our groups voted for what we each saw as priorities and those votes were tallied to create a final list for me to present in Redmond. Though there is obviously a great deal more we want to see in <abbr title=\"Internet Explorer\">IE</abbr>.next, we felt several things were critical and wanted to focus on those as a starting point.</p>\n<p>Tied for first place, in order of priority, were some sort of fast, arbitrary node-matching <abbr title=\"Application Programming Interface\">API</abbr> and better error reporting. In the realm of DOM Scripting, node-matching is key (just look at the number of scripts out there performing node matching based on CSS selectors, etc.), so being able to tap into a native XPath implementation (which we generally favored over the Selectors <abbr title=\"Application Programming Interface\">API</abbr>) would greatly improve the speed of script execution. As for the error reporting, perhaps Justin Palmer (of <abbr title=\"JavaScript\">JS</abbr> Ninjas) said it best:</p>\n<blockquote>\n<p>We could possibly find ways to fix all the other problems if we could tell what the hell was breaking and why. Without better error reporting, the remaining stuff on that list is just giving us a bigger gun to shoot ourselves in the foot with.</p>\n</blockquote>\n<p>Next up in our list was a desire for mutable DOM prototypes. This would address the issues that arise from <abbr title=\"Internet Explorer\">IE</abbr>’s implementation of DOM objects in JavaScript, where elements of the core DOM are not derived from the standard Object prototype. While not technically a standards-support issue, this request does not conflict with standards and it does provide JavaScript developers with the ability to address some of the issues the <abbr title=\"Internet Explorer\">IE</abbr> team may not be able to address themselves in the next release. As Andrew Dupont (another Ninja) remarked, <q>I think it’s reasonable to ask that a DOM implementation in JavaScript behave like it’s part of JavaScript.</q></p>\n<p>Next up was a biggie: bring <abbr title=\"Internet Explorer\">IE</abbr>’s event system in line with the <abbr title=\"World Wide Web Consortium\">W3C</abbr> event model. This has been an issue for a lot of developers and the code to equalize the two event systems makes up a significant chunk of all of the major <abbr title=\"JavaScript\">JS</abbr> libraries. Getting <abbr title=\"Internet Explorer\">IE</abbr> to implement the <abbr title=\"World Wide Web Consortium\">W3C</abbr> event system would be a real boon for standards support and would drop the size of many libraries considerably.</p>\n<p>Finally, the last of our top 5 was not a <abbr title=\"JavaScript\">JS</abbr> issue, but rather a CSS one: implement generated content. I don’t know that I really need to get into the reasons why this would be really nice to have.</p>\n<p>Two “honorable mentions” were included in the list as well: fixing the issues with <code>getAttribute()</code> and <code>setAttribute()</code> and starting to implement some of the features of <abbr title=\"JavaScript\">JS</abbr> 1.7 (such as block-scope variables using <code>let</code>, etc.).</p>\n<p>Not willing to let the <abbr title=\"Internet Explorer\">IE</abbr> team off that easy, the document presented also highlighted several other issues which really need addressing including (among others)</p>\n<ul>\n<li>fixing CSS bugs (including collapsing adjoining margins and <code>z-index</code>);</li>\n<li>various form control fixes (including implementations of the <code>button</code> element, <code>label</code>s, and the <code>disabled</code> attribute);</li>\n<li>correcting its support for <code>object</code>;</li>\n<li>adding support for the <code>q</code> element (which should be a breeze once generated content is enabled); and</li>\n<li>fixing attribute issues (such as <code>alt</code> being used for a tooltip, <code>cite</code> not being supported on <code>q</code> and <code>blockquote</code>, and <code>summary</code> not being supported on <code>table</code>s).</li>\n</ul>\n<h3>The meeting</h3>\n<p>In Redmond, I met with Pete LePage, a Product Manager at Microsoft Web Platform and Tools, and several other key members on the <abbr title=\"Internet Explorer\">IE</abbr> team. We discussed the list and its implications in great detail for nearly two hours. While I am not at liberty to discuss all of the details of the meeting, I can say for certain that the group I met with was keenly aware of the issues we brought up and are eager to address them. One team member even said that he could have easily guessed our top 5.</p>\n<p>The one concern they have—especially with regard to the event model and <code>getAttribute()</code>/<code>setAttribute()</code>—is that any adjustments they make to bring <abbr title=\"Internet Explorer\">IE</abbr> in line with the standards not “break the web” for the large number of sites using the proprietary <abbr title=\"Internet Explorer\">IE</abbr> event model, etc. We discussed this particular topic at length as it is a valid concern and I’m happy to say that I think we’re close to a solution on that front.</p>\n<p>I came away from this meeting with a real sense of hope about where <abbr title=\"Internet Explorer\">IE</abbr> is going and am really encouraged by their willingness to engage the standards community (and web developers as a whole) in dialog like this. We did not resolve every issue in our two-hour talk, but I was assured that this was only the first of many steps toward improving <abbr title=\"Internet Explorer\">IE</abbr>.next. The <abbr title=\"Internet Explorer\">IE</abbr> team wants to continue this conversation and to continue to elicit feedback from the web community as a whole as things progress.</p>\n","url":"https://www.aaron-gustafson.com/notebook/talking-with-microsoft-about-ienext/","tags":["Microsoft","web standards","browsers"],"date_published":"2007-02-04T18:49:50Z"}]}