<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Sam Richard on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Sam Richard</name>
  </author>
  <link href="https://web.dev/authors/samrichard/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/admin/5kuER6QRWs54zbYIJ4zS.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Our latest news, updates, and stories by Sam Richard.</subtitle>
  
  
  <entry>
    <title>New Progressive Web App training now available</title>
    <link href="https://web.dev/new-pwa-training/"/>
    <updated>2021-05-20T00:00:00Z</updated>
    <id>https://web.dev/new-pwa-training/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; The training described below is designed as material to teach to others in a workshop format. For a self-guided course check out &lt;a href=&quot;https://web.dev/learn/pwa/&quot;&gt;Learn PWA&lt;/a&gt;. This course is based on the below material, but designed for individuals to work through rather than a course to teach others. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;A lot has changed in the world of &lt;a href=&quot;https://web.dev/progressive-web-apps/&quot;&gt;Progressive Web Apps&lt;/a&gt; since we released our last set of PWA training over four years ago: CSS Grid achieved widespread implementation, PWAs came to desktops, and the &lt;a href=&quot;https://developer.chrome.com/blog/fugu-status/&quot; rel=&quot;noopener&quot;&gt;capabilities project&lt;/a&gt; has launched more than 25 new device-integration focused APIs, opening up brand new app segments that can be built entirely on the web. Today, we&#39;re excited to share the first iteration of our newly updated PWA training to teach you how to build reliable, installable, and capable Progressive Web Apps for all devices.&lt;/p&gt;
&lt;p&gt;The current version of the training is divided into six slide decks, ready for you to learn from or for you to pick up and teach to others. They are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/1w0BVEmtCQvmJGHK0OjOhr8HeNVGYi0ezGz81fimkDdE/edit?usp=sharing&quot; rel=&quot;noopener&quot;&gt;Introduction to Progressive Web Apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/1tJH05P8OfcDgUjNbW-oxZN9G-OtmDpA-lqNMy1M97Cs/edit?usp=sharing&amp;amp;resourcekey=0-UAAWbPgLxyrTBkqSSOj6GQ&quot; rel=&quot;noopener&quot;&gt;Creating a Solid Foundation for your PWA&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/1CwKVRauMW30SrHTgexnJQw2XBOZt_R6K6_NucmTkygY/edit#slide=id.p&quot; rel=&quot;noopener&quot;&gt;Improve the Reliability of your Web App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/1TBCK2b_yVov-DwHpRf8vWyEz2KqIu-gg8h-QOyss7HI/edit?resourcekey=0-GTzLs6UHZyQZ-tBG6LlOMQ&quot; rel=&quot;noopener&quot;&gt;Make your Web App Installable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/1m7U2iK-63aaTvMQGDwxtLgqWLg8RwH4Ba2AwFuTcxOo/edit&quot; rel=&quot;noopener&quot;&gt;Adding Advanced Capabilities to your Web App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/13KHsxknXSbADS1kRLYkS46YJr_AsImoW6r6VAjYj3dE/edit?resourcekey=0-MrN8aV43XaOE_FM18Vsn_Q#slide=id.p&quot; rel=&quot;noopener&quot;&gt;Adopting Advanced Web App Architectures&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To go along with this new material, there are eight new codelabs that will guide you through turning a web app into a Progressive Web App with deep device integration, using the concepts taught throughout the slide decks. You can jump into any codelab and work on it individually, or you can go through them one after another; the choice is yours. They are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/codelabs/pwa-training/pwa03--going-offline#0&quot; rel=&quot;noopener&quot;&gt;Going Offline&lt;/a&gt; - Basics of writing a service worker to cache and serve content offline&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/codelabs/pwa-training/pwa03--working-with-workbox&quot; rel=&quot;noopener&quot;&gt;Working with Workbox&lt;/a&gt; - Using &lt;a href=&quot;https://developer.chrome.com/docs/workbox/&quot; rel=&quot;noopener&quot;&gt;Workbox&lt;/a&gt; to write your service worker&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/codelabs/pwa-training/pwa03--indexeddb&quot; rel=&quot;noopener&quot;&gt;IndexedDB&lt;/a&gt; - Using IndexedDB to store and retrieve data&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/codelabs/pwa-training/pwa04--tab-to-taskbar&quot; rel=&quot;noopener&quot;&gt;Tab to Taskbar&lt;/a&gt; - Making your web app installable and providing app shortcuts&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/codelabs/pwa-training/pwa04--prompt-measure-install#5&quot; rel=&quot;noopener&quot;&gt;Prompting and Measuring Install&lt;/a&gt; - Adding in-app install prompts, and where to put success tracking&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/codelabs/pwa-training/pwa05--empowering-your-pwa#0&quot; rel=&quot;noopener&quot;&gt;Empowering your PWA&lt;/a&gt; - Adding advanced capabilities, including accessing the local file system and registering as a file handler&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/codelabs/pwa-training/pwa06--service-worker-includes#0&quot; rel=&quot;noopener&quot;&gt;Service Worker Includes&lt;/a&gt; - Dynamically generating a streaming service worker response&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/codelabs/pwa-training/pwa06--working-with-workers#0&quot; rel=&quot;noopener&quot;&gt;Working with Workers&lt;/a&gt; - Using web workers to offload work from the main thread&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Over the next few months, we&#39;ll be converting the slide deck content into easier-to-consume and update formats. This will make it easier for us to keep the content up-to-date, so no more waiting four years for another push of content. Keep an eye on this space. The future of web apps is exciting, and we&#39;re thrilled to teach you how to build it.&lt;/p&gt;
</content>
    <author>
      <name>Sam Richard</name>
    </author>
  </entry>
  
  <entry>
    <title>What makes a good Progressive Web App?</title>
    <link href="https://web.dev/pwa-checklist/"/>
    <updated>2020-01-06T00:00:00Z</updated>
    <id>https://web.dev/pwa-checklist/</id>
    <content type="html" mode="escaped">&lt;!-- Disable heading-increment because it mucks with the Details widget --&gt;
&lt;!--lint disable heading-increment--&gt;
&lt;p&gt;Progressive Web Apps (PWA) are built and enhanced with modern APIs to deliver
enhanced capabilities, reliability, and installability while reaching
&lt;em&gt;anyone, anywhere, on any device&lt;/em&gt; with a single codebase. To help you create
the best possible experience, use the &lt;a href=&quot;https://web.dev/pwa-checklist/#core&quot;&gt;core&lt;/a&gt; and &lt;a href=&quot;https://web.dev/pwa-checklist/#optimal&quot;&gt;optimal&lt;/a&gt;
checklists and recommendations to guide you.&lt;/p&gt;
&lt;h2 id=&quot;core&quot;&gt;Core Progressive Web App checklist &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#core&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Progressive Web App Checklist describes what makes an app installable and
usable by all users, regardless of size or input type.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;
  Starts fast, stays fast
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; Performance plays a significant role in the success of any online experience, because high performing sites engage and retain users better than poorly performing ones. Sites should focus on optimizing for user-centric performance metrics.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;Performance plays a significant role in the success of any online experience,
because high performing sites engage and retain users better than poorly
performing ones. Sites should focus on optimizing for user-centric performance metrics.&lt;/p&gt;
&lt;h4 id=&quot;why&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Speed is critical for getting users to &lt;em&gt;use&lt;/em&gt; your app.
In fact, as page load times go from one second to ten seconds, the probability of
a user bouncing increases by 123%. Performance doesn&#39;t stop with the &lt;code&gt;load&lt;/code&gt; event.
Users should never wonder whether their interaction—for example, clicking a
button—was registered or not. Scrolling and animation should feel smooth.
Performance affects your entire experience, from how users perceive your
application to how it actually performs.&lt;/p&gt;
&lt;p&gt;While all applications have different needs, the performance audits in
Lighthouse are based on the
&lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals&lt;/a&gt;,
and scoring high on those audits will make it more likely that your users have
an enjoyable experience. You can also use
&lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights&lt;/a&gt;
or the &lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome User Experience Report&lt;/a&gt;
to get real-world performance data for your web app.&lt;/p&gt;
&lt;h4 id=&quot;how&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Follow our &lt;a href=&quot;https://web.dev/fast/&quot;&gt;guide on fast load times&lt;/a&gt; to learn how to make your PWA
start fast and stay fast.&lt;/p&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;
  Works in any  browser
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; Users can use any browser they choose to access your web app before it&#39;s installed.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;Users can use any browser they choose to access your web app before it&#39;s
installed.&lt;/p&gt;
&lt;h4 id=&quot;why-2&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why-2&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Progressive Web Apps are web apps first, and that means they need to work
across browsers, not just in one of them.&lt;/p&gt;
&lt;p&gt;An effective way of doing this is by, in the words of Jeremy Keith in
&lt;a href=&quot;https://resilientwebdesign.com/&quot; rel=&quot;noopener&quot;&gt;Resilient Web Design&lt;/a&gt;, identifying the core
functionality, making that functionality available using the simplest possible
technology, and then enhancing the experience where possible. In many cases,
this means starting with just HTML to create the core functionality, and
enhancing the user experience with CSS and JavaScript to create a more
engaging experience.&lt;/p&gt;
&lt;p&gt;Take form submission for example. The simplest way to implement that is an
HTML form that submits a &lt;code&gt;POST&lt;/code&gt; request. After building that, you can enhance
the experience with JavaScript to do form validation and submit the form via
AJAX, improving the experience for users who can support it.&lt;/p&gt;
&lt;p&gt;Consider that your users will experience your site across a spectrum of
devices and browsers. You cannot simply target the top end of the spectrum.
By using feature detection, you&#39;ll be able to deliver a usable experience
for the widest range of potential users, including those using browsers
and devices that may not exist today.&lt;/p&gt;
&lt;h4 id=&quot;how-2&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how-2&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Jeremy Keith&#39;s &lt;a href=&quot;https://resilientwebdesign.com/&quot; rel=&quot;noopener&quot;&gt;Resilient Web Design&lt;/a&gt; is an
excellent resource describing how to think about web design in this
cross-browser, progressive methodology.&lt;/p&gt;
&lt;h4 id=&quot;additional-reading&quot;&gt;Additional reading &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#additional-reading&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;A List Apart&#39;s &lt;a href=&quot;https://alistapart.com/article/understandingprogressiveenhancement/&quot; rel=&quot;noopener&quot;&gt;Understanding Progressive Enhancement&lt;/a&gt;
is a good introduction to the topic.&lt;/li&gt;
&lt;li&gt;Smashing Magazine&#39;s
&lt;a href=&quot;https://www.smashingmagazine.com/2009/04/progressive-enhancement-what-it-is-and-how-to-use-it/&quot; rel=&quot;noopener&quot;&gt;Progressive Enhancement: What It Is, And How To Use It?&lt;/a&gt;
gives a practical introduction and links to more advanced topics.&lt;/li&gt;
&lt;li&gt;MDN has an article titled
&lt;a href=&quot;https://developer.mozilla.org/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection&quot; rel=&quot;noopener&quot;&gt;Implementing feature detection&lt;/a&gt;
that talks about how to detect a feature  by directly querying it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;
  Responsive to any screen size
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; Users can use your PWA on any screen size and all of the content is available at any viewport size.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;Users can use your PWA on any screen size and all of the content is available
at any viewport size.&lt;/p&gt;
&lt;h4 id=&quot;why-3&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why-3&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Devices come in a range of sizes, and users may use your application at a
range of sizes, even on the same device. Therefore, it&#39;s critical to ensure
your content not only fits within the viewport, but that all features and
content for your site are usable at all viewport sizes.&lt;/p&gt;
&lt;p&gt;The tasks users want to complete and the content they want to access do
not change with viewport size. The content can be rearranged at different
viewport sizes, and it should all be there, one way or another. In fact, as
Luke Wroblewski states in his book Mobile First, starting small and going
large instead of the other way around can actually improve a site&#39;s design:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mobile devices require software development teams to focus on only the
most important data and actions in an application. There simply isn&#39;t room
in a 320 by 480 pixel screen for extraneous, unnecessary elements.
You have to prioritize.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;how-3&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how-3&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;There are many  resources on responsive design, including the
&lt;a href=&quot;https://alistapart.com/article/responsive-web-design/&quot; rel=&quot;noopener&quot;&gt;original article by Ethan Marcotte&lt;/a&gt;,
a &lt;a href=&quot;https://snugug.com/musings/principles-responsive-web-design/&quot; rel=&quot;noopener&quot;&gt;collection of important concepts&lt;/a&gt;
related to it, as well as books and talks galore. To narrow this discussion
down to the content aspects of responsive design, you can dig into
&lt;a href=&quot;https://uxdesign.cc/why-you-should-design-the-content-first-for-better-experiences-374f4ba1fe3c&quot; rel=&quot;noopener&quot;&gt;content-first design&lt;/a&gt;
and &lt;a href=&quot;https://alistapart.com/article/content-out-layout/&quot; rel=&quot;noopener&quot;&gt;content-out responsive layouts&lt;/a&gt;.
Finally, while it&#39;s focused on mobile, the lessons in
&lt;a href=&quot;https://www.forbes.com/sites/anthonykosner/2012/05/03/seven-deadly-mobile-myths-josh-clark-debunks-the-desktop-paradigm-and-more/#21ecac977bca&quot; rel=&quot;noopener&quot;&gt;Seven Deadly Mobile Myths&lt;/a&gt;
by Josh Clark are just as relevant to small-sized views of responsive sites
as they are to mobile.&lt;/p&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;
  Provides a custom offline page
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; When users are offline, keeping them in your PWA provides a more seamless experience than dropping back to the default browser offline page.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;When users are offline, keeping them in your PWA provides a more seamless
experience than dropping back to the default browser offline
page.&lt;/p&gt;
&lt;h4 id=&quot;why-4&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why-4&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Users expect installed apps to work regardless of their connection status.
A platform-specific app never shows a blank page when it is offline, and a Progressive
Web App should never show the browser default offline page. Providing a
custom offline experience, both when a user navigates to a URL that hasn&#39;t
been cached and when a user tries to use a feature that requires a connection,
helps your web experience feel like it&#39;s part of the device it&#39;s running on.&lt;/p&gt;
&lt;h4 id=&quot;how-4&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how-4&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;During a service worker&#39;s &lt;code&gt;install&lt;/code&gt; event, you can precache a custom offline
page for later use. If a user goes offline, you can respond with the precached
custom offline page. You can follow our custom
&lt;a href=&quot;https://googlechrome.github.io/samples/service-worker/custom-offline-page/&quot; rel=&quot;noopener&quot;&gt;offline page sample&lt;/a&gt;
to see an example of this in action and learn how to implement it yourself.&lt;/p&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;
  Is installable
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; Users who install or add apps to their device tend to engage with those apps more.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;Users who install or add apps to their device tend to engage with those
apps more.&lt;/p&gt;
&lt;h4 id=&quot;why-5&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why-5&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Installing a Progressive Web App allows it to look, feel, and behave like all
other installed apps. It&#39;s launched from the same place users launch their
other apps. It runs in its own app window, separate from the browser, and it
appears in the task list, just like other apps.&lt;/p&gt;
&lt;p&gt;Why would you want a user to install your PWA? The same reason you&#39;d want a
user to install your app from an app store. Users who install your apps
are your most engaged audience, and have better engagement metrics than
typical visitors, often at parity with app users on mobile devices.
These metrics include more repeat visits, longer times on your site and
higher conversion rates.&lt;/p&gt;
&lt;h4 id=&quot;how-5&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how-5&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;You can follow our &lt;a href=&quot;https://web.dev/customize-install/&quot;&gt;installable guide&lt;/a&gt; to learn how to make
your PWA installable, how to test to see that it&#39;s installable, and try
doing it yourself.&lt;/p&gt;
&lt;/details&gt;
&lt;h2 id=&quot;optimal&quot;&gt;Optimal Progressive Web App checklist &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#optimal&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To create a truly great Progressive Web App, one that feels like a
best-in-class app, you need more than just the core checklist. The optimal
Progressive Web App checklist is about making your PWA feel like it&#39;s part
of the device it&#39;s running on while taking advantage of what makes the web powerful.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;
  Provides an offline experience
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; Where connectivity isn&#39;t strictly required, your app works the same offline as it does online.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;Where connectivity isn&#39;t strictly required, your app works the same offline
as it does online.&lt;/p&gt;
&lt;h4 id=&quot;why-6&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why-6&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In addition to providing a custom offline page, users expect Progressive Web
Apps to be usable offline. For example, travel and airline apps should have
trip details and boarding passes easily available when offline. Music,
video, and podcasting apps should allow for offline playback. Social and
news apps should cache recent content so users can read it when offline.
Users also expect to stay authenticated when offline, so design for
offline authentication. An offline PWA provides a true app-like experience
for users.&lt;/p&gt;
&lt;h4 id=&quot;how-6&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how-6&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;After determining which features your users expect to work offline, you&#39;ll
need to make your content available and adaptable to offline contexts. In
addition, you can use
&lt;a href=&quot;https://web.dev/indexeddb/&quot;&gt;IndexedDB&lt;/a&gt;,
an in-browser NoSQL storage system, to store and retrieve data, and
&lt;a href=&quot;https://developer.chrome.com/blog/background-sync/&quot; rel=&quot;noopener&quot;&gt;background sync&lt;/a&gt;
to allow users to take actions while offline and defer server communications
until the user has a stable connection again. You can also use service
workers to store other kinds of content, such as images, video files, and
audio files for offline use, as well as use them to implement
&lt;a href=&quot;https://developer.chrome.com/blog/2-cookie-handoff/&quot; rel=&quot;noopener&quot;&gt;safe, long-lived sessions&lt;/a&gt;
to keep users authenticated. From a user experience perspective, you can use
&lt;a href=&quot;https://uxdesign.cc/what-you-should-know-about-skeleton-screens-a820c45a571a&quot; rel=&quot;noopener&quot;&gt;skeleton screens&lt;/a&gt;
that give users a perception of speed and content while loading that can
then fall back to cached content or an offline indicator as needed.&lt;/p&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;
  Is fully accessible
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; All user interactions pass &lt;a href=&quot;https://www.w3.org/TR/WCAG20/&quot;&gt;WCAG 2.0&lt;/a&gt; accessibility requirements.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;All user interactions pass &lt;a href=&quot;https://www.w3.org/TR/WCAG20/&quot; rel=&quot;noopener&quot;&gt;WCAG 2.0&lt;/a&gt;
accessibility requirements.&lt;/p&gt;
&lt;h4 id=&quot;why-7&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why-7&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Most people at some point in their life will want to take advantage of your
PWA in a way that is covered under the &lt;a href=&quot;https://www.w3.org/TR/WCAG20/&quot; rel=&quot;noopener&quot;&gt;WCAG 2.0&lt;/a&gt;
accessibility requirements. Humans&#39; ability to interact with and understand
your PWA exist on a spectrum and needs can be temporary or permanent. By
making your PWA accessible, you ensure it&#39;s usable for everyone.&lt;/p&gt;
&lt;h4 id=&quot;how-7&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how-7&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;W3C&#39;s &lt;a href=&quot;https://www.w3.org/WAI/fundamentals/accessibility-intro/&quot; rel=&quot;noopener&quot;&gt;Introduction to Web Accessibility&lt;/a&gt;
is a good place to start. A majority of accessibility testing
must be done manually. Tools like the &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/accessibility/&quot; rel=&quot;noopener&quot;&gt;Accessibility&lt;/a&gt;
audits in Lighthouse, &lt;a href=&quot;https://github.com/dequelabs/axe-core&quot; rel=&quot;noopener&quot;&gt;axe&lt;/a&gt;, and
&lt;a href=&quot;https://accessibilityinsights.io/&quot; rel=&quot;noopener&quot;&gt;Accessibility Insights&lt;/a&gt; can help you
automate some accessibility testing. It&#39;s also important to use semantically
correct elements instead of recreating those elements on your own,
for instance, &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;button&lt;/code&gt; elements. This ensures that when you do need
to build more advanced functionality, accessible expectations are met (such as
when to use arrows vs. tabs).
&lt;a href=&quot;https://accessibilityinsights.io/&quot; rel=&quot;noopener&quot;&gt;A11Y Nutrition Cards&lt;/a&gt; has excellent
advice on this for some common components.&lt;/p&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;
  Can be discovered through search
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; Your PWA can be easily &lt;a href=&quot;https://web.dev/discoverable/&quot;&gt;discovered through search&lt;/a&gt;.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;Your PWA can be easily &lt;a href=&quot;https://web.dev/discoverable/&quot;&gt;discovered through search&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;why-8&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why-8&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;One of the biggest advantages of the web is the ability to discover sites and
apps through search. In fact,
&lt;a href=&quot;https://www.brightedge.com/resources/research-reports/channel_share&quot; rel=&quot;noopener&quot;&gt;more than half&lt;/a&gt;
of all website traffic comes from organic search. Making sure that canonical
URLs exist for content and that search engines can index your site is critical
for users to be able to find your PWA. This is especially true when adopting
client-side rendering.&lt;/p&gt;
&lt;h4 id=&quot;how-8&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how-8&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Start by ensuring that each URL has a unique, descriptive title and meta
description. Then you can use the
&lt;a href=&quot;https://search.google.com/search-console/about&quot; rel=&quot;noopener&quot;&gt;Google Search Console&lt;/a&gt;
and the &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/seo/&quot; rel=&quot;noopener&quot;&gt;Search Engine Optimization audits&lt;/a&gt; in Lighthouse to
help you debug and fix discoverability issues with your PWA. You can also use
&lt;a href=&quot;https://www.bing.com/toolbox/webmaster&quot; rel=&quot;noopener&quot;&gt;Bing&lt;/a&gt;&#39;s or
&lt;a href=&quot;https://webmaster.yandex.com/welcome/&quot; rel=&quot;noopener&quot;&gt;Yandex&lt;/a&gt;&#39;s webmaster tools, and
consider including &lt;a href=&quot;https://goo.gle/search-gallery&quot; rel=&quot;noopener&quot;&gt;structured data&lt;/a&gt; via
schemas from &lt;a href=&quot;https://schema.org/&quot; rel=&quot;noopener&quot;&gt;Schema.org&lt;/a&gt; in your PWA.&lt;/p&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;
  Works with any input type
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; Your PWA is equally usable with a mouse, a keyboard, a stylus, or touch.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;Your PWA is equally usable with a mouse, a keyboard, a stylus, or touch.&lt;/p&gt;
&lt;h4 id=&quot;why-9&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why-9&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Devices offer a variety of input methods, and users should be able to
seamlessly switch between them while using your application. Just as important,
input methods should not depend on screen size, meaning that large viewports
need to support touch and small viewports need to support keyboards and mice.
To the best of your ability, ensure that your application and all of its
features supports usage of any input method your user may choose to use.
Where appropriate, you should also enhance experiences to allow for
input-specific controls as well (such as pull-to-refresh).&lt;/p&gt;
&lt;h4 id=&quot;how-9&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how-9&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/blog/pointer-events/&quot; rel=&quot;noopener&quot;&gt;Pointer Events API&lt;/a&gt;
provides a unified interface for working with various input options, and is
especially good for adding stylus support. For supporting both touch and
keyboard, ensure that you&#39;re using the correct semantic elements (anchors,
buttons, form controls, etc.) and not rebuilding these with non-semantic
HTML (which is good for accessibility). When including interactions that
activate on hover, ensure they can activate on click or tap, too.&lt;/p&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;
  Provides context for permission requests
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; When asking permission to use powerful APIs, provide context and ask only when the API is needed.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;When asking permission to use powerful APIs, provide context and ask only
when the API is needed.&lt;/p&gt;
&lt;h4 id=&quot;why-10&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why-10&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;APIs that trigger a permission prompt, like notifications, geolocation, and
credentials, are intentionally designed to be disruptive to a user because they
tend to be related to powerful functionality that requires opt-in. Triggering
these prompts without additional context, like on page load, makes users
less likely to accept those permissions and more likely to distrust them
in the future. Instead, only trigger those prompts after providing an
in-context rationale to the user for why you need that permission.&lt;/p&gt;
&lt;h4 id=&quot;how-10&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how-10&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The &lt;a href=&quot;https://web.dev/push-notifications-permissions-ux/&quot;&gt;Permission UX&lt;/a&gt;
article and UX Planet&#39;s
&lt;a href=&quot;https://uxplanet.org/mobile-ux-design-the-right-ways-to-ask-users-for-permissions-6cdd9ab25c27&quot; rel=&quot;noopener&quot;&gt;The Right Ways to Ask Users for Permissions&lt;/a&gt;
are good resources to understand how to design permission prompts that, while
focused on mobile, apply to all PWAs.&lt;/p&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;
  Follows best practices for healthy code
  &lt;p class=&quot;text-base color-core-text gap-top-base&quot;&gt; Keeping your codebase healthy makes it easier to meet your goals and deliver new features.&lt;/p&gt;
&lt;/summary&gt;
&lt;p&gt;Keeping your codebase healthy makes it easier to meet your goals and deliver
new features.&lt;/p&gt;
&lt;h4 id=&quot;why-11&quot;&gt;Why &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#why-11&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;There&#39;s a lot that goes into building a modern web application. Keeping your
application up-to-date and your codebase healthy makes it easier for you to
deliver new features that meet the other goals laid out in this checklist.&lt;/p&gt;
&lt;h4 id=&quot;how-11&quot;&gt;How &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/pwa-checklist/#how-11&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;There are a number of high-priority checks to ensure a healthy
codebase: avoiding using libraries with known vulnerabilities, ensuring
you&#39;re not using deprecated APIs, removing web anti-patterns from your
codebase (like using &lt;code&gt;document.write()&lt;/code&gt; or having non-passive scroll event
listeners), and even coding defensively to ensure your PWA doesn&#39;t break
if analytics or other third party libraries fail to load. Consider requiring
static code analysis, like linting, as well as automated testing, in multiple
browsers and release channels. These techniques can help catch errors
before they make it into production.&lt;/p&gt;
&lt;/details&gt;
</content>
    <author>
      <name>Sam Richard</name>
    </author><author>
      <name>Pete LePage</name>
    </author>
  </entry>
  
  <entry>
    <title>What are Progressive Web Apps?</title>
    <link href="https://web.dev/what-are-pwas/"/>
    <updated>2020-01-06T00:00:00Z</updated>
    <id>https://web.dev/what-are-pwas/</id>
    <content type="html" mode="escaped">&lt;p&gt;The web is an incredible platform. Its mix of ubiquity across devices and
operating systems, its user-centered security model, and the fact that neither
its specification nor its implementation are controlled by a single company makes
the web a unique platform to develop software on. Combined with its inherent
linkability, it&#39;s possible to search it and share what you&#39;ve found with
anyone, anywhere. Whenever you go to a website, it&#39;s up-to-date, and your
experience with that site can be as ephemeral or as permanent as you&#39;d like. Web
applications can reach &lt;em&gt;anyone, anywhere, on any device&lt;/em&gt; with a single codebase.&lt;/p&gt;
&lt;p&gt;Platform-specific applications are known for being incredibly rich and reliable. They&#39;re
ever-present, on home screens, docks, and taskbars. They work regardless of
network connection. They launch in their own standalone experience. They can
read and write files from the local file system, access hardware connected via
USB, serial port, or bluetooth, and even interact with data stored on your device,
such as contacts and calendar events. In these applications, you can do things
such as take pictures, see playing songs listed on the home screen, or control song
playback while in another app. Platform-specific applications feel like &lt;em&gt;part&lt;/em&gt; of the
device they run on.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A graph illustrating the relative capabilites and reach of platform-specific apps, with high capabilities, web apps, with high reach, and progressive web apps, which have both high capabilities and high reach.&quot; decoding=&quot;async&quot; height=&quot;367&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1DKtUFjXLJbiiruKA9P1.svg&quot; width=&quot;370&quot; /&gt;
  &lt;figcaption&gt;
    Capabilities vs. reach of platform-specific apps, web apps, and progressive web apps.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;If you think about platform-specific apps and web apps in terms of capabilities and reach,
platform-specific apps represent the best of capabilities whereas web apps represent the
best of reach. So where do Progressive Web Apps fit in?&lt;/p&gt;
&lt;p&gt;Progressive Web Apps (PWA) are built and enhanced with modern APIs to deliver
enhanced capabilities, reliability, and installability while reaching
&lt;em&gt;anyone, anywhere, on any device&lt;/em&gt; with a single codebase.&lt;/p&gt;
&lt;h2 id=&quot;the-three-app-pillars&quot;&gt;The three app pillars &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/what-are-pwas/#the-three-app-pillars&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Progressive Web Apps are web applications that have been designed to be
capable, reliable, and installable. These three pillars transform them into an
experience that feels like a platform-specific application.&lt;/p&gt;
&lt;h3 id=&quot;capable&quot;&gt;Capable &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/what-are-pwas/#capable&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The web is quite capable in its own right today. For example, you can build a hyper-local
video chat app using WebRTC, geolocation, and push notifications. You can make
that app installable and take its conversations virtual with WebGL and WebVR.
With the introduction of WebAssembly, developers can tap into other ecosystems,
such as C, C++, and Rust, and bring decades of work and capabilities to the web.
&lt;a href=&quot;https://squoosh.app/&quot; rel=&quot;noopener&quot;&gt;Squoosh.app&lt;/a&gt;, for instance, uses this for its
advanced image compression.&lt;/p&gt;
&lt;p&gt;Until recently, only platform-specific apps could really lay claim to these capabilities.
While some capabilities are still out of the web&#39;s reach, new and upcoming APIs
are looking to change that, expanding what the web can do with features like
file system access, media controls, app badging, and full clipboard support. All
of these capabilities are built with the web&#39;s secure, user-centric permission
model, ensuring that going to a website is never scary for users.&lt;/p&gt;
&lt;p&gt;Between modern APIs, WebAssembly, and new and upcoming APIs, web applications
are more capable than ever, and those capabilities are only growing.&lt;/p&gt;
&lt;h3 id=&quot;reliable&quot;&gt;Reliable &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/what-are-pwas/#reliable&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A reliable Progressive Web App feels fast and dependable regardless of the
network.&lt;/p&gt;
&lt;p&gt;Speed is critical for getting users to &lt;em&gt;use&lt;/em&gt; your experience. In fact, as page
load times go from 1 second to ten seconds, the probability of a user bouncing
&lt;a href=&quot;https://www.thinkwithgoogle.com/marketing-resources/data-measurement/mobile-page-speed-new-industry-benchmarks/&quot; rel=&quot;noopener&quot;&gt;increases by 123%&lt;/a&gt;.
Performance doesn&#39;t stop after the &lt;code&gt;onload&lt;/code&gt; event. Users should never wonder whether their
interaction—for example, clicking a button—was registered or not. Scrolling and
animation should feel smooth. Performance affects the entire user experience, from
how they perceive your application to how it actually performs.&lt;/p&gt;
&lt;p&gt;Finally, reliable applications need to be usable regardless of network
connection. Users expect apps to start up on slow or flaky network connections
or even when offline. They expect the most recent content they&#39;ve interacted
with, such as media tracks or tickets and itineraries, to be available and usable
even if getting a request to your server is hard. When a request isn&#39;t possible,
they expect to be told there&#39;s trouble instead of silently failing or crashing.&lt;/p&gt;
&lt;p&gt;Users deserve apps that respond to interaction in the blink of an eye, and an
experience they can depend on.&lt;/p&gt;
&lt;h3 id=&quot;installable&quot;&gt;Installable &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/what-are-pwas/#installable&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Installed Progressive Web Apps run in a standalone window instead of a browser
tab. They&#39;re launchable from on the user&#39;s home screen, dock, taskbar, or shelf.
It&#39;s possible to search for them on a device and jump between them with the app
switcher, making them feel like part of the device they&#39;re installed on.&lt;/p&gt;
&lt;p&gt;New capabilities open up after a web app is installed. Keyboard shortcuts, usually
reserved when running in the browser, become available. Progressive Web
Apps can register to accept content from other applications, or to be the
default application to handle different types of files.&lt;/p&gt;
&lt;p&gt;When a Progressive Web App moves out of a tab and into a standalone app window,
it transforms how users think about it and interact with it.&lt;/p&gt;
&lt;h2 id=&quot;the-best-of-both-worlds&quot;&gt;The best of both worlds &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/what-are-pwas/#the-best-of-both-worlds&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At their heart, Progressive Web Apps are just web applications. Using
progressive enhancement, new capabilities are enabled in modern browsers. Using
service workers and a web app manifest, your web application becomes reliable
and installable. If the new capabilities aren&#39;t available, users still get the core experience.&lt;/p&gt;
&lt;p&gt;The numbers don&#39;t lie! Companies that have launched Progressive Web Apps have
seen impressive results. For example, Twitter saw a 65% increase in pages per
session, 75% more Tweets, and a 20% decrease in bounce rate, all while reducing
the size of their app by over 97%. After switching to a PWA, Nikkei saw 2.3
times more organic traffic, 58% more subscriptions, and 49% more daily active
users. Hulu replaced their platform-specific desktop experience with a Progressive Web App
and saw a 27% increase in return visits.&lt;/p&gt;
&lt;p&gt;Progressive Web Apps provide you with a unique opportunity to deliver a web
experience your users will love. Using the latest web features to bring
enhanced capabilities and reliability, Progressive Web Apps allow what you
build to be installed by &lt;em&gt;anyone, anywhere, on any device&lt;/em&gt; with a single
codebase.&lt;/p&gt;
&lt;!--lint disable no-unescaped-template-tags--&gt;
&lt;script type=&quot;speculationRules&quot;&gt;
{
  &quot;prerender&quot;:[
    {
      &quot;source&quot;:&quot;list&quot;,
      &quot;urls&quot;:[
        &quot;/progressive-web-apps/&quot;
      ]
    }
  ]
}
&lt;/script&gt;
&lt;!--lint enable no-unescaped-template-tags--&gt;
</content>
    <author>
      <name>Sam Richard</name>
    </author><author>
      <name>Pete LePage</name>
    </author>
  </entry>
  
  <entry>
    <title>Integrate PWAs into built-in sharing UIs with Workbox</title>
    <link href="https://web.dev/workbox-share-targets/"/>
    <updated>2019-12-19T00:00:00Z</updated>
    <id>https://web.dev/workbox-share-targets/</id>
    <content type="html" mode="escaped">&lt;p&gt;The &lt;a href=&quot;https://web.dev/web-share-target/&quot;&gt;Web Share Target API&lt;/a&gt; lets you display
your &lt;a href=&quot;https://web.dev/pwa-checklist/&quot;&gt;Progressive Web App&lt;/a&gt; in a
user&#39;s system-level share &lt;a href=&quot;https://material.io/develop/android/components/bottom-sheet-behavior/&quot; rel=&quot;noopener&quot;&gt;sheet&lt;/a&gt; after it&#39;s been installed. While it works great if you have a server
available to receive the request, it&#39;s much harder to get working if you don&#39;t.&lt;/p&gt;
&lt;p&gt;In this article we&#39;ll use
&lt;a href=&quot;https://developer.chrome.com/docs/workbox/&quot; rel=&quot;noopener&quot;&gt;Workbox&lt;/a&gt;, a set of JavaScript
libraries for adding offline support to web apps, to create a share target URL
that lives entirely inside your &lt;a href=&quot;https://web.dev/service-workers-cache-storage/&quot;&gt;service worker&lt;/a&gt;. This lets static sites and
single-page apps serve as share targets without a dedicated server endpoint.&lt;/p&gt;
&lt;figure data-float=&quot;right&quot;&gt;
  &lt;img alt=&quot;Android phone with the &amp;#x27;Share via&amp;#x27; drawer open.&quot; decoding=&quot;async&quot; height=&quot;377&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 400px) 400px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/mp2bdiP2gVeMQ4UX12vd.png?auto=format&amp;w=800 800w&quot; width=&quot;400&quot; /&gt;
  &lt;figcaption&gt;
    System-level share target picker with an installed PWA called
    &lt;code&gt;Share Target Test&lt;/code&gt; as an option.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;on-the-same-page&quot;&gt;On the same page &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/workbox-share-targets/#on-the-same-page&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re unfamiliar with how Web Share Target Works, &lt;a href=&quot;https://web.dev/web-share-target/&quot;&gt;Receiving shared data with the Web Share
Target API&lt;/a&gt; gives you an in-depth introduction.
Here&#39;s a quick review.&lt;/p&gt;
&lt;p&gt;There are two parts to implementing web share target functionality. First,
update your &lt;a href=&quot;https://web.dev/add-manifest/&quot;&gt;web app manifest&lt;/a&gt; to indicate that you want your app to be a share
target when installed. The following example directs shares to the &lt;code&gt;/share&lt;/code&gt; url
via a &lt;code&gt;POST&lt;/code&gt; request. It is encoded as a multipart form, with title being called
&lt;code&gt;name&lt;/code&gt;, text being called &lt;code&gt;description&lt;/code&gt;, and JPEG images being called &lt;code&gt;photos&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;…&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;&quot;share_target&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/share&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;method&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;enctype&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;multipart/form-data&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;params&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;files&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;photos&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token property&quot;&gt;&quot;accept&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;image/jpeg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.jpg&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;…&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;service-worker-share-targets-with-workbox&quot;&gt;Service worker share targets with Workbox &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/workbox-share-targets/#service-worker-share-targets-with-workbox&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While normally handled by a server endpoint, a neat trick you can do for a share
target is to register a route directly in your service worker to handle the
request. This will let your app be a share target without a backend.&lt;/p&gt;
&lt;p&gt;You do this in &lt;a href=&quot;https://developer.chrome.com/docs/workbox/&quot; rel=&quot;noopener&quot;&gt;Workbox&lt;/a&gt; by
registering a route that&#39;s handled by your service worker. Start by importing
&lt;code&gt;registerRoute&lt;/code&gt; from &lt;code&gt;&#39;workbox-routing&#39;&lt;/code&gt;. Notice that it&#39;s registered for the
&lt;code&gt;/share&lt;/code&gt; route, the same one listed in the example web app manifest. In
response it calls &lt;code&gt;shareTargetHandler()&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; registerRoute &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;workbox-routing&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;registerRoute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&#39;/share&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  shareTargetHandler&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string&quot;&gt;&#39;POST&#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;shareTargetHandler()&lt;/code&gt; function is asynchronous and takes the event, awaits
the form data, then retrieves the media files from that.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shareTargetHandler&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; formData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;formData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mediaFiles &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; formData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;media&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mediaFile &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; mediaFiles&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Do something with mediaFile&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Maybe cache it or post it back to a server&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Do something with the rest of formData as you need&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Maybe save it to IndexedDB&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can then do whatever you&#39;d like with these files. You can cache them. You
can send them somewhere with a fetch request. You can even use the other
manifest options, maybe serving a page with some query parameters for the other
shared items or storing the data and pointers to the media in the &lt;a href=&quot;https://web.dev/cache-api-quick-guide/&quot;&gt;Cache Storage
API&lt;/a&gt;
or &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/IndexedDB_API&quot; rel=&quot;noopener&quot;&gt;IndexedDB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can try it out on the sample app &lt;a href=&quot;https://fugu-journal.web.app/&quot; rel=&quot;noopener&quot;&gt;Fugu
Journal&lt;/a&gt; and see its service worker
implementation in its &lt;a href=&quot;https://github.com/chromeos/bridging-the-native-app-gap/blob/master/fugu-journal/src/js/service-worker.js&quot; rel=&quot;noopener&quot;&gt;source
code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One common thing you might do is hold shared resources until better network
connections are available. Workbox also supports &lt;a href=&quot;https://web.dev/periodic-background-sync/&quot;&gt;periodic background
sync&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/workbox-share-targets/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Share Target API is a simple way to deeply integrate your Progressive Web
App into user&#39;s devices, putting them on-par with platform-specific applications for the
critical task of sharing content between apps. But doing so usually requires a
server available to receive the request. By leveraging Workbox to create a share
target route directly in your service worker, your app is free of this
constraint, allowing Share Target to work for apps while offline and without
backends.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@ecasap?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot; rel=&quot;noopener&quot;&gt;Elaine Casap&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/s/photos/share?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot; rel=&quot;noopener&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
</content>
    <author>
      <name>Sam Richard</name>
    </author><author>
      <name>Joe Medley</name>
    </author><author>
      <name>Jeff Posnick</name>
    </author>
  </entry>
  
  <entry>
    <title>Smarter custom properties with Houdini’s new API</title>
    <link href="https://web.dev/css-props-and-vals/"/>
    <updated>2019-09-19T00:00:00Z</updated>
    <id>https://web.dev/css-props-and-vals/</id>
    <content type="html" mode="escaped">&lt;p&gt;CSS custom properties, also known as &lt;a href=&quot;https://developer.chrome.com/blog/css-variables-why-should-you-care/&quot; rel=&quot;noopener&quot;&gt;CSS
variables&lt;/a&gt;,
let you define your own properties in CSS and use their values throughout your
CSS. While incredibly useful today, they have shortcomings that can make them
hard to work with: they can take any value so they may be accidentally
overridden with something unexpected, they always inherit their values from
their parent, and you can&#39;t transition them. With Houdini&#39;s &lt;a href=&quot;https://drafts.css-houdini.org/css-properties-values-api/&quot; rel=&quot;noopener&quot;&gt;CSS Properties and
Values API Level 1&lt;/a&gt;,
now available in Chrome 78, these shortcomings are transcended, making CSS
custom properties incredibly powerful!&lt;/p&gt;
&lt;h2 id=&quot;what-is-houdini&quot;&gt;What Is Houdini? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-props-and-vals/#what-is-houdini&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before talking about the new API, let&#39;s talk about Houdini quickly. The CSS-TAG
Houdini Task Force, better known as CSS Houdini or simply Houdini, exists to
&amp;quot;develop features that explain the &#39;magic&#39; of styling and layout on the web&amp;quot;.
The collection of &lt;a href=&quot;https://drafts.css-houdini.org/&quot; rel=&quot;noopener&quot;&gt;Houdini specifications&lt;/a&gt; are
designed to open up the power of the browser&#39;s rendering engine, allowing both
deeper insight into our styles and the ability to extend our rendering engine.
With this, typed CSS values in JavaScript and polyfilling or inventing new CSS
without a performance hit are finally possible. Houdini has the potential to
superpower creativity on the web.&lt;/p&gt;
&lt;h2 id=&quot;css-properties-and-values-api-level-1&quot;&gt;CSS Properties and Values API Level 1 &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-props-and-vals/#css-properties-and-values-api-level-1&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://drafts.css-houdini.org/css-properties-values-api/&quot; rel=&quot;noopener&quot;&gt;CSS Properties and Values API Level
1&lt;/a&gt; (Houdini Props and
Vals) allows us to give structure to our custom properties. This is the current
situation when using custom properties:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.thing&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--my-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Because custom properties don&#39;t have types, they can be overridden in unexpected
ways. For example, consider what happens if you define &lt;code&gt;--my-color&lt;/code&gt; with a URL.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.thing&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--my-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&#39;not-a-color&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--my-color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Here, because &lt;code&gt;--my-color&lt;/code&gt; isn&#39;t typed, it doesn&#39;t know that a URL isn&#39;t a valid
color value! When we use it, it falls back to default values (black for &lt;code&gt;color&lt;/code&gt;,
transparent for &lt;code&gt;background&lt;/code&gt;). With Houdini Props and Vals, custom properties can
be &lt;em&gt;registered&lt;/em&gt; so that the browser knows what it &lt;em&gt;should&lt;/em&gt; be!&lt;/p&gt;
&lt;p&gt;Now, the custom property &lt;code&gt;--my-color&lt;/code&gt; is registered as a color! This tells the
browser what kinds of values are allowed and how it can type and treat that
property!&lt;/p&gt;
&lt;h3 id=&quot;anatomy-of-a-registered-property&quot;&gt;Anatomy of a registered property &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-props-and-vals/#anatomy-of-a-registered-property&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Registering a property looks like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;--my-color&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;syntax&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;color&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;inherits&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;initialValue&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;black&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It supports the following options:&lt;/p&gt;
&lt;h4 id=&quot;name-string&quot;&gt;&lt;code&gt;name: string&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-props-and-vals/#name-string&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The name of the custom property.&lt;/p&gt;
&lt;h4 id=&quot;syntax-string&quot;&gt;&lt;code&gt;syntax: string&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-props-and-vals/#syntax-string&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;How to parse the custom property. You can find a complete list of possible values in the &lt;a href=&quot;https://drafts.csswg.org/css-values-3/&quot;&gt;CSS Values and Units&lt;/a&gt; specification. Defaults to &lt;code&gt;*&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;inherits-boolean&quot;&gt;&lt;code&gt;inherits: boolean&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-props-and-vals/#inherits-boolean&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Whether it inherits its parent&#39;s value. Defaults to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;initialvalue-string&quot;&gt;&lt;code&gt;initialValue: string&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-props-and-vals/#initialvalue-string&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Initial value of the custom property.&lt;/p&gt;
&lt;p&gt;Taking a closer look at &lt;code&gt;syntax&lt;/code&gt;. There are a number of &lt;a href=&quot;https://drafts.css-houdini.org/css-properties-values-api/#supported-names&quot; rel=&quot;noopener&quot;&gt;valid
options&lt;/a&gt;
ranging from numbers to colors to
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/custom-ident&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;custom-ident&amp;gt;&lt;/code&gt;&lt;/a&gt;
types. These syntaxes can also be modified by using the following values&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Appending &lt;code&gt;+&lt;/code&gt; signifies that it accepts a space-separated list of values of
that syntax. For example,  &lt;code&gt;&amp;lt;length&amp;gt;+&lt;/code&gt; would be a space-separated list of
lengths&lt;/li&gt;
&lt;li&gt;Appending&lt;code&gt;#&lt;/code&gt; signifies that it accepts a comma-separated list of values of
that syntax. For example,  &lt;code&gt;&amp;lt;color&amp;gt;#&lt;/code&gt; would be a comma-separated list of
colors&lt;/li&gt;
&lt;li&gt;Adding &lt;code&gt;|&lt;/code&gt; between syntaxes or identifiers signifies that any of the provided
options are valid. For example, &lt;code&gt;&amp;lt;color&amp;gt;# | &amp;lt;url&amp;gt; | magic&lt;/code&gt; would allow either
a comma-separated list of colors, a URL, or the word &lt;code&gt;magic&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;gotchas&quot;&gt;Gotchas &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-props-and-vals/#gotchas&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are two gotchas with Houdini Props and Vals. The first is that, once
defined, there&#39;s no way to update an existing registered property, and trying to
re-register a property will throw an error indicating that it&#39;s already been
defined.&lt;/p&gt;
&lt;p&gt;Second, unlike standard properties, registered properties aren&#39;t validated when
they&#39;re parsed. Rather they&#39;re validated when they&#39;re computed. That means both
that invalid values won&#39;t appear as invalid when inspecting the element&#39;s
properties, and including an invalid property after a valid one won&#39;t fall back
to the valid one; an invalid property will, however, fall back to the registered
property&#39;s default.&lt;/p&gt;
&lt;h2 id=&quot;animating-custom-properties&quot;&gt;Animating custom properties &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-props-and-vals/#animating-custom-properties&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A registered custom property provides a fun bonus beyond type checking: the
ability to animate it! A basic animation example looks like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token constant&quot;&gt;CSS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;--stop-color&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;syntax&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;color&gt;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;inherits&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;initialValue&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;blue&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token style&quot;&gt;&lt;span class=&quot;token language-css&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--stop-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; --stop-color 1s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;button:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--stop-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When you hover over the button, it&#39;ll animate from red to green! Without
registering the property, it&#39;ll jump from one color to the other Because,
without being registered, the browser doesn&#39;t know what to expect between one
value and the next and therefore can&#39;t guarantee the ability to transition them.
This example can be taken a step further, though, to animate CSS gradients! The
following CSS can be written with the same registered property:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--stop-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; red&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;linear-gradient&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;--stop-color&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; black&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;transition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; --stop-color 1s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;button:hover&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;--stop-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; green&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This will animate our custom property that&#39;s part of the &lt;code&gt;linear-gradient&lt;/code&gt;, thus
animating our linear gradient. Check out the Glitch below to see the full code
in action and play around with it yourself.&lt;/p&gt;
&lt;!-- Copy and Paste Me --&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 420px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/houdini-props-and-vals?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=style.css&amp;previewSize=40&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;houdini-props-and-vals on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/css-props-and-vals/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Houdini &lt;a href=&quot;http://ishoudinireadyyet.com/&quot; rel=&quot;noopener&quot;&gt;is on its way&lt;/a&gt; to browsers, and with it,
entirely new ways of working with and extending CSS. With the &lt;a href=&quot;https://developer.chrome.com/blog/paintapi&quot; rel=&quot;noopener&quot;&gt;Paint
API&lt;/a&gt; already shipped
and now Custom Props and Vals, our creative toolbox is expanding, allowing us to
define typed CSS properties and use them to create and animate new and exciting
designs. There&#39;s more on the way, too, in the &lt;a href=&quot;https://github.com/w3c/css-houdini-drafts/issues&quot; rel=&quot;noopener&quot;&gt;Houdini issue
queue&lt;/a&gt; where you can give
feedback and see what&#39;s next for Houdini. Houdini exists to develop features
that explain the &amp;quot;magic&amp;quot; of styling and layout on the web, so get out there and
put those magical features to good use.&lt;/p&gt;
&lt;!--lint disable no-literal-urls--&gt;
&lt;p&gt;&lt;em&gt;Photo by
&lt;a href=&quot;https://unsplash.com/@der_maik_?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot; rel=&quot;noopener&quot;&gt;Maik Jonietz&lt;/a&gt;
on
&lt;a href=&quot;https://unsplash.com/search/photos/code?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText&quot; rel=&quot;noopener&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Sam Richard</name>
    </author>
  </entry>
</feed>
