<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Arthur Evans on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Arthur Evans</name>
  </author>
  <link href="https://web.dev/authors/arthurevans/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/admin/e0IbHjXAuzFNqSnnZMcp.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Arthur is a Tech Writer</subtitle>
  
  
  <entry>
    <title>More capable form controls</title>
    <link href="https://web.dev/more-capable-form-controls/"/>
    <updated>2019-08-08T00:00:00Z</updated>
    <id>https://web.dev/more-capable-form-controls/</id>
    <content type="html" mode="escaped">&lt;p&gt;Many developers build custom form controls, either to provide controls that aren&#39;t built in to the browser, or to customize the look and feel beyond what&#39;s possible with the built-in form controls.&lt;/p&gt;
&lt;p&gt;However, it can be difficult to replicate the features of built-in HTML form controls. Consider some of the features an &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element gets automatically when you add it to a form:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The input is automatically added to the form&#39;s list of controls.&lt;/li&gt;
&lt;li&gt;The input&#39;s value is automatically submitted with the form.&lt;/li&gt;
&lt;li&gt;The input participates in &lt;a href=&quot;https://developer.mozilla.org/docs/Learn/HTML/Forms/Form_validation&quot; rel=&quot;noopener&quot;&gt;form validation&lt;/a&gt;. You can style the input using the &lt;code&gt;:valid&lt;/code&gt; and &lt;code&gt;:invalid&lt;/code&gt; pseudoclasses.&lt;/li&gt;
&lt;li&gt;The input is notified when the form is reset, when the form is reloaded, or when the browser tries to autofill form entries.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Custom form controls typically have few of these features. Developers can work around some of the limitations in JavaScript, like adding a hidden &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; to a form to participate in form submission. But other features just can&#39;t be replicated in JavaScript alone.&lt;/p&gt;
&lt;p&gt;Two new web features make it easier to build custom form controls, and remove the limitations of current custom controls:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;formdata&lt;/code&gt; event lets an arbitrary JavaScript object participate in form submission, so you can add form data without using a hidden &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The Form-associated custom elements API lets custom elements act more like built-in form controls.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These two features can be used to create new kinds of controls that work better.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;Building custom form controls is an advanced topic. This article assumes a certain knowledge of forms and form controls. When building a custom form control, there are many factors to consider, especially making sure that your controls are accessible to all users. To learn more about forms, go to the &lt;a href=&quot;https://developer.mozilla.org/docs/Learn/HTML/Forms&quot;&gt;MDN guide on forms&lt;/a&gt;.&lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;event-based-api&quot;&gt;Event-based API &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#event-based-api&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;formdata&lt;/code&gt; event is a low-level API that lets any JavaScript code participate in form submission. The mechanism works like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You add a &lt;code&gt;formdata&lt;/code&gt; event listener to the form you want to interact with.&lt;/li&gt;
&lt;li&gt;When a user clicks the submit button, the form fires a &lt;code&gt;formdata&lt;/code&gt; event, which includes a &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/FormData&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;FormData&lt;/code&gt;&lt;/a&gt; object that holds all of the data being submitted.&lt;/li&gt;
&lt;li&gt;Each &lt;code&gt;formdata&lt;/code&gt; listener gets a chance to add to or modify the data before the form is submitted.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&#39;s an example of sending a single value in a &lt;code&gt;formdata&lt;/code&gt; event listener:&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;const&lt;/span&gt; form &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;form&#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;span class=&quot;token comment&quot;&gt;// FormData event is sent on &amp;lt;form&gt; submission, before transmission.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// The event has a formData property&lt;/span&gt;&lt;br /&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;formdata&#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;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;formData&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 operator&quot;&gt;=&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;// https://developer.mozilla.org/docs/Web/API/FormData&lt;/span&gt;&lt;br /&gt;  formData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-input&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; myInputValue&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;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;Try this out using our example on Glitch. Be sure to run it on Chrome 77 or later to see the API in action.&lt;/p&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/formdata-event?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=index.html&amp;previewSize=0&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;formdata-event on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&quot;browser-compatibility&quot;&gt;Browser compatibility &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#browser-compatibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 5, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      5
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 4, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      4
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 12, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      12
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 5, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      5
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/API/FormData#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;h2 id=&quot;form-associated-custom-elements&quot;&gt;Form-associated custom elements &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#form-associated-custom-elements&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can use the event-based API with any kind of component, but it only allows you to interact with the submission process.&lt;/p&gt;
&lt;p&gt;Standardized form controls participate in many parts of the form lifecycle besides submission. Form-associated custom elements aim to bridge the gap between custom widgets and built-in controls. Form-associated custom elements match many of the features of standardized form elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When you place a form-associated custom element inside a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;, it&#39;s automatically associated with the form, like a browser-provided control.&lt;/li&gt;
&lt;li&gt;The element can be labeled using a &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;The element can set a value that&#39;s automatically submitted with the form.&lt;/li&gt;
&lt;li&gt;The element can set a flag indicating whether or not it has valid input. If one of the form controls has invalid input, the form can&#39;t be submitted.&lt;/li&gt;
&lt;li&gt;The element can provide callbacks for various parts of the form lifecycle—such as when the form is disabled or reset to its default state.&lt;/li&gt;
&lt;li&gt;The element supports the standard CSS pseudoclasses for form controls, like &lt;code&gt;:disabled&lt;/code&gt; and &lt;code&gt;:invalid&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&#39;s a lot of features! This article won&#39;t touch on all of them, but will describe the basics needed to integrate your custom element with a form.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;This section assumes a basic familiarity with custom elements. For an introduction to custom elements, see &lt;a href=&quot;https://web.dev/custom-elements-v1/&quot;&gt;Custom Elements v1: Reusable Web Components&lt;/a&gt; on Web Fundamentals.&lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;defining-a-form-associated-custom-element&quot;&gt;Defining a form-associated custom element &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#defining-a-form-associated-custom-element&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To turn a custom element into a form-associated custom element requires a few extra steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add a static &lt;code&gt;formAssociated&lt;/code&gt; property to your custom element class. This tells the browser to treat the element like a form control.&lt;/li&gt;
&lt;li&gt;Call the &lt;code&gt;attachInternals()&lt;/code&gt; method on the element to get access to extra methods and properties for form controls, like &lt;code&gt;setFormValue()&lt;/code&gt; and &lt;code&gt;setValidity()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the common properties and methods supported by form controls, like &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;value&lt;/code&gt;, and &lt;code&gt;validity&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&#39;s how those items fit into a basic custom element definition:&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 comment&quot;&gt;// Form-associated custom elements must be autonomous custom elements--&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// meaning they must extend HTMLElement, not one of its subclasses.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyCounter&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLElement&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;// Identify the element as a form-associated custom element&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; formAssociated &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&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;constructor&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;super&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 comment&quot;&gt;// Get access to the internal form control APIs&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;attachInternals&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 comment&quot;&gt;// internal value for this control&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&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;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Form controls usually expose a &quot;value&quot; property&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;value&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_&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;set&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;v&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 keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; v&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;// The following properties and methods aren&#39;t strictly required,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// but browser-level form controls provide them. Providing them helps&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// ensure consistency with browser-provided controls.&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;form&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;form&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;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;name&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;name&#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;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;type&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;localName&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;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;validity&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;validity&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;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;validationMessage&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;validationMessage&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;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;willValidate&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;willValidate&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 function&quot;&gt;checkValidity&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;checkValidity&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;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;reportValidity&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;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reportValidity&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;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  …&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;customElements&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;my-counter&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MyCounter&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;Once registered, you can use this element wherever you&#39;d use a browser-provided form control:&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;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&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;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Number of bunnies: &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;my-counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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;my-counter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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;label&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&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;button&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;submit&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Submit&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;button&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&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;form&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;h3 id=&quot;setting-a-value&quot;&gt;Setting a value &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#setting-a-value&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;attachInternals()&lt;/code&gt; method returns an &lt;code&gt;ElementInternals&lt;/code&gt; object that provides access to form control APIs. The most basic of these is the &lt;code&gt;setFormValue()&lt;/code&gt; method, which sets the current value of the control.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;setFormValue()&lt;/code&gt; method can take one of three types of values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A string value.&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/File&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;File&lt;/code&gt;&lt;/a&gt; object.&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/FormData&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;FormData&lt;/code&gt;&lt;/a&gt; object. You can use a &lt;code&gt;FormData&lt;/code&gt; object to pass multiple values (for example, a credit card input control might pass a card number, expiration date, and verification code).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To set a simple value:&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;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setFormValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_&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;To set multiple values, you can do something like this:&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 comment&quot;&gt;// Use the control&#39;s name as the base name for submitted data&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;name&#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;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; entries &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&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;entries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;-first-name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;firstName_&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;entries&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;-last-name&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lastName_&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;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setFormValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entries&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;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;The &lt;code&gt;setFormValue()&lt;/code&gt; method takes a second, optional &lt;code&gt;state&lt;/code&gt; parameter, used to store the internal state of the control. For more information, see &lt;a href=&quot;https://web.dev/more-capable-form-controls/#restoring-form-state&quot;&gt;Restoring form state&lt;/a&gt;.&lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;input-validation&quot;&gt;Input validation &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#input-validation&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Your control can also participate in form validation by calling the &lt;code&gt;setValidity()&lt;/code&gt;
method on the internals object.&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 comment&quot;&gt;// Assume this is called whenever the internal value is updated&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;onUpdateValue&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;:disabled&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;required&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_ &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&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;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setValidity&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 literal-property property&quot;&gt;customError&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&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 string&quot;&gt;&#39;Value cannot be negative.&#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;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;else&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;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setValidity&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;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;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setFormValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_&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;You can style a form-associated custom element with the &lt;code&gt;:valid&lt;/code&gt; and &lt;code&gt;:invalid&lt;/code&gt;
pseudoclasses, just like a built-in form control.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt;Although you can set a validation message, Chrome currently fails to display the validation message for form-associated custom elements.&lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;lifecycle-callbacks&quot;&gt;Lifecycle callbacks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#lifecycle-callbacks&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A form-associated custom element API includes a set of extra lifecycle callbacks to tie in to the form lifecycle. The callbacks are optional: only implement a callback if your element needs to do something at that point in the lifecycle.&lt;/p&gt;
&lt;h4 id=&quot;void-formassociatedcallbackform&quot;&gt;&lt;code&gt;void formAssociatedCallback(form)&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#void-formassociatedcallbackform&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Called when the browser associates the element with a form element, or disassociates the element from a form element.&lt;/p&gt;
&lt;h4 id=&quot;void-formdisabledcallbackdisabled&quot;&gt;&lt;code&gt;void formDisabledCallback(disabled)&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#void-formdisabledcallbackdisabled&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Called after the &lt;code&gt;disabled&lt;/code&gt; state of the element changes, either because the &lt;code&gt;disabled&lt;/code&gt; attribute of this element was added or removed; or because the &lt;code&gt;disabled&lt;/code&gt; state changed on a &lt;code&gt;&amp;lt;fieldset&amp;gt;&lt;/code&gt; that&#39;s an ancestor of this element. The &lt;code&gt;disabled&lt;/code&gt; parameter represents the new &lt;a href=&quot;https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-fe-disabled&quot; rel=&quot;noopener&quot;&gt;disabled state&lt;/a&gt; of the element. The element may, for example, disable elements in its shadow DOM when it is disabled.&lt;/p&gt;
&lt;h4 id=&quot;void-formresetcallback&quot;&gt;&lt;code&gt;void formResetCallback()&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#void-formresetcallback&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Called after the form is reset. The element should reset itself to some kind of default state. For &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; elements, this usually involves setting the &lt;code&gt;value&lt;/code&gt; property to match the &lt;code&gt;value&lt;/code&gt; attribute set in markup (or in the case of a checkbox, setting the &lt;code&gt;checked&lt;/code&gt; property to match the &lt;code&gt;checked&lt;/code&gt; attribute.&lt;/p&gt;
&lt;h4 id=&quot;void-formstaterestorecallbackstate,-mode&quot;&gt;&lt;code&gt;void formStateRestoreCallback(state, mode)&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#void-formstaterestorecallbackstate,-mode&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Called in one of two circumstances:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When the browser restores the state of the element (for example, after a navigation, or when the browser restarts).  The &lt;code&gt;mode&lt;/code&gt; argument is &lt;code&gt;&amp;quot;restore&amp;quot;&lt;/code&gt; in this case.&lt;/li&gt;
&lt;li&gt;When the browser&#39;s input-assist features such as form autofilling sets a value. The &lt;code&gt;mode&lt;/code&gt; argument is &lt;code&gt;&amp;quot;autocomplete&amp;quot;&lt;/code&gt; in this case.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The type of the first argument depends on how the &lt;code&gt;setFormValue()&lt;/code&gt; method was called. For more details, see &lt;a href=&quot;https://web.dev/more-capable-form-controls/#restoring-form-state&quot;&gt;Restoring form state&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;restoring-form-state&quot;&gt;Restoring form state &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#restoring-form-state&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Under some circumstances—like when navigating back to a page, or restarting the browser, the browser may try to restore the form to the state the user left it in.&lt;/p&gt;
&lt;p&gt;For a form-associated custom element, the restored state comes from the value(s) you pass to the &lt;code&gt;setFormValue()&lt;/code&gt; method. You can call the method with a single value parameter, as shown in the &lt;a href=&quot;https://web.dev/more-capable-form-controls/#set-a-value&quot;&gt;earlier examples&lt;/a&gt;, or with two parameters:&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;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setFormValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; state&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;value&lt;/code&gt; represents the submittable value of the control. The optional &lt;code&gt;state&lt;/code&gt; parameter is an &lt;em&gt;internal&lt;/em&gt; representation of the state of the control, which can include data that doesn&#39;t get sent to the server. The &lt;code&gt;state&lt;/code&gt; parameter takes the same types as the &lt;code&gt;value&lt;/code&gt; parameter—it can be a string, &lt;code&gt;File&lt;/code&gt;, or &lt;code&gt;FormData&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;state&lt;/code&gt; parameter is useful when you can&#39;t restore a control&#39;s state based on the value alone. For example, suppose you create a color picker with multiple modes: a palette or an RGB color wheel. The submittable &lt;em&gt;value&lt;/em&gt; would be the selected color in a canonical form, like &lt;code&gt;&amp;quot;#7fff00&amp;quot;&lt;/code&gt;. But to restore the control to a specific state, you&#39;d also need to know which mode it was in, so the &lt;em&gt;state&lt;/em&gt; might look like &lt;code&gt;&amp;quot;palette/#7fff00&amp;quot;&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;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;internals_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setFormValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mode_ &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_&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;Your code would need to restore its state based on the stored state value.&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 function&quot;&gt;formStateRestoreCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mode&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mode &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;restore&#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;span class=&quot;token comment&quot;&gt;// expects a state parameter in the form &#39;controlMode/value&#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;controlMode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/&#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;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mode_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; controlMode&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value&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 comment&quot;&gt;// Chrome currently doesn&#39;t handle autofill for form-associated&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// custom elements. In the autofill case, you might need to handle&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// a raw value.&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;In the case of a simpler control (for example a number input), the value is probably sufficient to restore the control to its previous state. If you omit &lt;code&gt;state&lt;/code&gt; when calling &lt;code&gt;setFormValue()&lt;/code&gt;, then the value is passed to &lt;code&gt;formStateRestoreCallback()&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 function&quot;&gt;formStateRestoreCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mode&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 comment&quot;&gt;// Simple case, restore the saved value&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; state&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;h3 id=&quot;a-working-example&quot;&gt;A working example &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#a-working-example&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The following example puts together many of the features of form-associated custom elements.
Be sure to run it on Chrome 77 or later to see the API in action.&lt;/p&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/form-associated-ce?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=public%2Fmy-control.js&amp;previewSize=0&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;form-associated-ce on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&quot;feature-detection&quot;&gt;Feature detection &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#feature-detection&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can use feature detection to determine whether the &lt;code&gt;formdata&lt;/code&gt; event and form-associated custom elements are available. There are currently no polyfills released for either feature. In both cases, you can fall back to adding a hidden form element to propagate the control&#39;s value to the form. Many of the more advanced features of form-associated custom elements will likely be difficult or impossible to polyfill.&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;FormDataEvent&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; window&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;// formdata event is supported&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 keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;ElementInternals&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; window &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&#39;setFormValue&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ElementInternals&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&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;// Form-associated custom elements are supported&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;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/more-capable-form-controls/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;formdata&lt;/code&gt; event and form-associated custom elements provide new tools for creating custom form controls.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;formdata&lt;/code&gt; event doesn&#39;t give you any new capabilities, but it gives you an interface for adding your form data to the submit process, without having to create a hidden &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;The form-associated custom elements API provides a new set of capabilities for making custom form controls that work like built-in form controls.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hero image by Oudom Pravat on &lt;a href=&quot;https://unsplash.com/photos/yQi4mAFmRew&quot; rel=&quot;noopener&quot;&gt;Unsplash&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Arthur Evans</name>
    </author>
  </entry>
  
  <entry>
    <title>Web components: the secret ingredient helping power the web</title>
    <link href="https://web.dev/web-components-io-2019/"/>
    <updated>2019-06-18T00:00:00Z</updated>
    <id>https://web.dev/web-components-io-2019/</id>
    <content type="html" mode="escaped">&lt;p&gt;At Google I/O 2019, Kevin Schaaf of the Polymer Project and Caridy Patiño of Salesforce talked about the state of web components.&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;YBwgkr_Sbx0&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;h2 id=&quot;how-popular-are-web-components&quot;&gt;How popular are web components? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-components-io-2019/#how-popular-are-web-components&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;ve used the web today, you&#39;ve probably used web components. By our count, somewhere between 5% and 8% of all page loads today use one or more web components. That makes web components one of the most successful new web platform features shipped in the last five years.&lt;/p&gt;
&lt;figure data-size=&quot;full&quot;&gt;
  &lt;img alt=&quot;A graph showing that 8% of sites use v1 custom elements. This figure eclipses the 5% highpoint for v0 custom elements.&quot; decoding=&quot;async&quot; height=&quot;493&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/RYVwr119hwQIps5UL0u4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;You can find web components on sites you probably use every day, like YouTube and GitHub. They&#39;re also used on many news and publishing sites built with &lt;a href=&quot;http://amp.dev/&quot; rel=&quot;noopener&quot;&gt;AMP&lt;/a&gt;—AMP components are also web components. And many enterprises are also adopting web components.&lt;/p&gt;
&lt;h2 id=&quot;what-are-web-components&quot;&gt;What are web components? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-components-io-2019/#what-are-web-components&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So what are web components? The web components specifications provide a low-level set of APIs that let you extend the browser&#39;s built-in set of HTML tags. Web components provide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A common method for creating a component (using standard DOM APIs).&lt;/li&gt;
&lt;li&gt;A common way of receiving and sending data (using properties/events).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Outside of that standard interface, the standards don&#39;t say anything about how a component is actually implemented:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What rendering engine it uses to create its DOM.&lt;/li&gt;
&lt;li&gt;How it updates itself based on changes to its properties or attributes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, web components  tell the browser &lt;strong&gt;when&lt;/strong&gt; and &lt;strong&gt;where&lt;/strong&gt; to make a component, but not &lt;strong&gt;how&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Authors can choose functional rendering patterns just like React to build their web components, or they can use declarative templates like you might find in Angular or Vue. As an author you have total freedom to choose the technology you use inside the component, while still maintaining interoperability.&lt;/p&gt;
&lt;h2 id=&quot;what-are-web-components-good-for&quot;&gt;What are web components good for? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-components-io-2019/#what-are-web-components-good-for&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The key difference between web components and proprietary component systems is  &lt;strong&gt;interoperability&lt;/strong&gt;. Because of their standard interface, you can use web components anywhere you&#39;d use a built-in element like &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Because they can be expressed as real HTML, they can be rendered by all the popular frameworks. So your components can be consumed more widely, in a more diverse range of applications, without locking users into any one framework.&lt;/p&gt;
&lt;p&gt;And because the component interface is standard, web components implemented using different libraries can be mixed on the same page. This fact helps future-proof your applications when you update your tech stack. Instead of a giant step-change between one framework and another, where you replace all of your components, you can update your components one at a time.&lt;/p&gt;
&lt;h2 id=&quot;whos-using-web-components&quot;&gt;Who&#39;s using web components? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-components-io-2019/#whos-using-web-components&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So for all of these reasons, Web Components are actually finding huge success in a variety of different use cases. Three use cases have been especially popular: content sites, design systems, and enterprise applications.&lt;/p&gt;
&lt;h3 id=&quot;content-sites&quot;&gt;Content sites &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-components-io-2019/#content-sites&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Web components are the perfect technology for progressively enhancing content, because they can already be output as standard HTML by an untold number of CMS systems.&lt;/p&gt;
&lt;p&gt;AMP is a great example of how quickly and easily Web Components slotted into the publishing industry&#39;s infrastructure for serving content.&lt;/p&gt;
&lt;h3 id=&quot;design-systems&quot;&gt;Design systems &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-components-io-2019/#design-systems&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;More and more companies are unifying the way they present themselves using a design system—a set of components and guidelines that define the common look and feel for an organization&#39;s sites and applications. Web components are a great fit here, too.&lt;/p&gt;
&lt;figure data-size=&quot;full&quot;&gt;
  &lt;img alt=&quot;The material design homepage, https://material.io.&quot; decoding=&quot;async&quot; height=&quot;736&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/xFG8pvgZDYTWQvx4W5i2.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Often, designers have to contend with many teams building their own versions of the design system components on top of React, Angular, and all the other frameworks, instead of having a single set of canonical components.&lt;/p&gt;
&lt;p&gt;Web components are the answer—a truly write once, run everywhere component system that still gives app teams freedom to use the framework of their choice&lt;/p&gt;
&lt;p&gt;Companies like ING, EA, and Google are implementing their company&#39;s design language in web components.&lt;/p&gt;
&lt;h3 id=&quot;enterprise-web-components-at-salesforce&quot;&gt;Enterprise: Web components at Salesforce &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-components-io-2019/#enterprise-web-components-at-salesforce&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Web components are also hitting a remarkable stride inside enterprises as a safe, future-proof technology to standardize on. Caridy Patiño, architect for Salesforce&#39;s UI platform, explained why they built their UI platform using web components.&lt;/p&gt;
&lt;p&gt;Salesforce is a collection of applications—many of which came from acquisitions. Each of these may run on its own technology stack. Because they&#39;re built on different stacks, it&#39;s hard to give them all the same look and feel. In addition, Salesforce enables customers to build their own custom applications using the Salesforce platform. So ideally the components should be usable by outside developers, too.&lt;/p&gt;
&lt;p&gt;Salesforce identified a set of needs from customers of their platform:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standard, rather than proprietary solutions—so it&#39;s easier to find experienced developers, and quicker to ramp up new developers.&lt;/li&gt;
&lt;li&gt;A common component model—so customizing any Salesforce application works the same way.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They also identified some things customers &lt;em&gt;didn&#39;t&lt;/em&gt; want:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Breaking changes on their components and apps. In other words, backwards compatibility was a must.&lt;/li&gt;
&lt;li&gt;Being stuck with old technology, and unable to evolve.&lt;/li&gt;
&lt;li&gt;Being stuck inside a walled garden.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using web components as the basis for the new UI platform met all of these needs, and the result is the new &lt;a href=&quot;https://developer.salesforce.com/docs/component-library/documentation/lwc&quot; rel=&quot;noopener&quot;&gt;Lightning Web Components&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;get-started-with-web-components&quot;&gt;Get started with web components &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/web-components-io-2019/#get-started-with-web-components&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a lot of great ways to get started with web components.&lt;/p&gt;
&lt;p&gt;If you&#39;re building a web app, consider using some of the many off-the-shelf web components available. Here are just a few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google vends its own Material design system as web components: &lt;a href=&quot;https://github.com/material-components/material-components-web-components&quot; rel=&quot;noopener&quot;&gt;Material Web Components&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://wiredjs.com/&quot; rel=&quot;noopener&quot;&gt;Wired Elements&lt;/a&gt; are a cool set of web components that feature a sketchy, hand-drawn look.&lt;/li&gt;
&lt;li&gt;There are great special-purpose Web Components like &lt;a href=&quot;https://github.com/GoogleWebComponents/model-viewer&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;model-viewer&amp;gt;&lt;/code&gt;&lt;/a&gt;, which you can drop into any app to add 3D content.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&#39;re developing a design system for your company, or you&#39;re vending a single component or library that you want to be usable in any environment, consider authoring your components using web components. You can use the built-in web components APIs, but they&#39;re pretty low-level, so there are a number of libraries available to make the process easier.&lt;/p&gt;
&lt;p&gt;To get started building your own components, you can check out LitElement, a web component base class developed by Google that has a great functional rendering experience similar to React.&lt;/p&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/lit-element-simple?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=my-component.js&amp;previewSize=0&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;lit-element-simple on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Other tools and libraries to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stenciljs.com/&quot; rel=&quot;noopener&quot;&gt;Stencil&lt;/a&gt; is a web-components-first framework. It includes several popular framework features, like JSX and TypeScript&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://angular.io/guide/elements&quot; rel=&quot;noopener&quot;&gt;Angular Elements&lt;/a&gt; provides a way to wrap Angular components as web components.&lt;/li&gt;
&lt;li&gt;Vue.js &lt;a href=&quot;https://github.com/vuejs/vue-web-component-wrapper&quot; rel=&quot;noopener&quot;&gt;web component wrapper&lt;/a&gt; provides a way to package Vue components as web components.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://open-wc.org/&quot; rel=&quot;noopener&quot;&gt;open-wc.org&lt;/a&gt; features great getting started information, as well as tips and default configurations for build and development tooling.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/web-components/&quot;&gt;Web Fundamentals&lt;/a&gt; provides primers on the basic web components APIs, and best practices for designing web components.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Web_Components&quot; rel=&quot;noopener&quot;&gt;MDN&lt;/a&gt; provides reference docs for the web components APIs, plus some tutorials. \&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Hero image by Jason Tuinstra on Unsplash.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Editor&#39;s note: The custom elements usage chart has been updated to show the
full monthly usage data, as reported on
&lt;a href=&quot;http://chromestatus.com/&quot; rel=&quot;noopener&quot;&gt;chromestatus.com&lt;/a&gt;. A previous version of this post
included a graph at a 6-month granularity, without the most recent months. The
V0 &amp;amp; V1 series in the original chart were stacked; they are now shown unstacked
with a total line to remove ambiguity. The abrupt jump in late 2017 is due to a
change in the data collection system for chromestatus.com. This change affected
the stats for all web platform features and resulted in more accurate
measurements going forward.&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Arthur Evans</name>
    </author>
  </entry>
  
  <entry>
    <title>Loading Third-Party JavaScript</title>
    <link href="https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/"/>
    <updated>2018-02-28T00:00:00Z</updated>
    <id>https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/</id>
    <content type="html" mode="escaped">&lt;p&gt;You&#39;ve optimized all of your code, but your site still loads too slowly. Who&#39;s
the culprit?&lt;/p&gt;
&lt;p&gt;Often, performance problems slowing pages down are due to third-party scripts:
ads, analytics, trackers, social media buttons, and so on.&lt;/p&gt;
&lt;p&gt;Third-party scripts provide a wide range of useful functionality, making the web
more dynamic, interactive, and interconnected. These scripts may be crucial to
your website&#39;s functionality or revenue stream. But third-party scripts also
come with &lt;strong&gt;many risks&lt;/strong&gt; that should be taken into consideration to &lt;strong&gt;minimize their impact&lt;/strong&gt; while still providing value.&lt;/p&gt;
&lt;p&gt;Why do you need to be
&lt;a href=&quot;https://css-tricks.com/potential-dangers-of-third-party-javascript/&quot; rel=&quot;noopener&quot;&gt;careful&lt;/a&gt;
about third-party scripts?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They can be a &lt;strong&gt;performance&lt;/strong&gt; concern&lt;/li&gt;
&lt;li&gt;They can be a &lt;strong&gt;privacy&lt;/strong&gt; concern&lt;/li&gt;
&lt;li&gt;They might be a &lt;strong&gt;security&lt;/strong&gt; concern&lt;/li&gt;
&lt;li&gt;They can be &lt;strong&gt;unpredictable&lt;/strong&gt; and change without you knowing&lt;/li&gt;
&lt;li&gt;They can have &lt;strong&gt;unintended consequences&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ideally, you’ll want to ensure third-party script is not impacting the &lt;a href=&quot;https://web.dev/critical-rendering-path/&quot;&gt;critical rendering path&lt;/a&gt;. In this
guide, we’ll walk through how to find and fix issues related to loading
third-party JavaScript.&lt;/p&gt;
&lt;h2 id=&quot;what-do-we-mean-by-third-party-scripts&quot;&gt;What do we mean by third-party scripts? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#what-do-we-mean-by-third-party-scripts&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Third-party JavaScript often refers to scripts that can be embedded into any
site directly from a third-party vendor. These scripts can include ads,
analytics, widgets and other scripts that make the web more dynamic and
interactive.&lt;/p&gt;
&lt;p&gt;Examples of third-party scripts include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Social sharing buttons (Twitter, Facebook, G+)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Video player embeds (YouTube, Vimeo)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Advertising iframes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Analytics &amp;amp; metrics scripts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A/B testing scripts for experiments&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Helper libraries (such as date formatting, animation, or functional libraries)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;example of a youtube video embed&quot; decoding=&quot;async&quot; height=&quot;267&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/OmUCDlDPThYWSHrbkLz0.jpeg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&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;iframe&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;560&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;315&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://www.youtube.com/embed/mo8thg5XGV0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;frameborder&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;allow&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;autoplay; encrypted-media&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;allowfullscreen&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&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;iframe&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;One example of this is the YouTube video player embed script that allows you to
embed a video into your page.&lt;/p&gt;
&lt;p&gt;Unfortunately, embedding third-party scripts means we often rely on them to be
fast in order to avoid slowing our pages down. Third-party scripts are a
predominant cause of performance slowdowns and are often caused by resources
outside of your control.&lt;/p&gt;
&lt;p&gt;These issues can include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Firing too many network requests to multiple servers. The more requests a site
has to make, the longer it can take to load.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sending &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/bootup-time/&quot; rel=&quot;noopener&quot;&gt;too much JavaScript&lt;/a&gt;
that keeps the main thread busy. Too much JavaScript can block DOM
construction, delaying how quickly pages can render. CPU-intensive script
parsing and execution can delay user interaction and cause battery drain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sending large, &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-optimized-images/&quot; rel=&quot;noopener&quot;&gt;unoptimized image files&lt;/a&gt; or videos. This can
consume data and cost users money.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Third-party scripts loaded without care can be a &lt;a href=&quot;http://blog.patrickmeenan.com/2011/10/testing-for-frontend-spof.html&quot; rel=&quot;noopener&quot;&gt;single-point of failure&lt;/a&gt;
(SPOF)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Insufficient &lt;a href=&quot;https://web.dev/http-cache/&quot;&gt;HTTP caching&lt;/a&gt;,
forcing resources to be fetched from the network often&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lack of sufficient &lt;a href=&quot;https://web.dev/optimizing-content-efficiency-optimize-encoding-and-transfer/&quot;&gt;server compression&lt;/a&gt;
of resources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Blocking content display until they complete processing. This can also be true
for async A/B testing scripts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use of legacy APIs (e.g &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/best-practices/no-document-write/&quot; rel=&quot;noopener&quot;&gt;document.write()&lt;/a&gt;) known to be harmful to the user experience&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Excessive DOM elements or expensive CSS selectors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Including multiple third-party embeds can lead to multiple frameworks and
libraries being pulled in several times. This is wasteful and exacerbates the
performance issues.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Third-party scripts often use embed techniques that can block
&lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/API/GlobalEventHandlers/onload&quot; rel=&quot;noopener&quot;&gt;window.onload&lt;/a&gt;
if their servers respond slowly, even if the embed is using async or defer.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Context is important and the solution to costly third-parties can depend on your
site and your ability to configure how you load third-party code. Thankfully, a
number of solutions and tools exist to find and fix issues with third-party
resources.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-identify-third-party-script-on-a-page&quot;&gt;How do you identify third-party script on a page? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#how-do-you-identify-third-party-script-on-a-page&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Unless you’re aware which third-party scripts are loaded by your site and what
their performance impact is, it’s impossible to know how to optimize them. Many
free web speed test tools can highlight costly third-parties including &lt;a href=&quot;https://developer.chrome.com/docs/devtools/&quot; rel=&quot;noopener&quot;&gt;Chrome DevTools&lt;/a&gt;, &lt;a href=&quot;https://pagespeed.web.dev/&quot; rel=&quot;noopener&quot;&gt;PageSpeed Insights&lt;/a&gt; and
&lt;a href=&quot;https://www.webpagetest.org/&quot; rel=&quot;noopener&quot;&gt;WebPageTest&lt;/a&gt;. These tools display rich diagnostic
information that can tell you &lt;em&gt;how many&lt;/em&gt; third-party scripts your
site is loading, and which take the most time to execute.&lt;/p&gt;
&lt;p&gt;WebPageTest’s waterfall view can highlight the impact of heavy third-party
script use. Below is an example of the requests required to load the main
content for a site vs. the tracking and marketing scripts (credit: &lt;a href=&quot;https://nystudio107.com/blog/tags-gone-wild&quot; rel=&quot;noopener&quot;&gt;Tags Gone Wild&lt;/a&gt;).&lt;/p&gt;
&lt;img alt=&quot;waterfall view from webpagetest showing an actual website vs the amount of time spent loading tracking scripts&quot; decoding=&quot;async&quot; height=&quot;983&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/e7SFcerlECyUqQqxm20M.jpeg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;WebPageTest’s &lt;a href=&quot;https://www.google.com/url?q=https://www.webpagetest.org/result/180222_J4_8fee6855d6f45719e4f37d8d89ecbc20/1/domains/&amp;amp;sa=D&amp;amp;ust=1519325015196000&amp;amp;usg=AFQjCNGrRivilJS9yqqpombsUMQZQJx2nw&quot; rel=&quot;noopener&quot;&gt;domain breakdown&lt;/a&gt;
can also be useful for visualizing how much content comes from third-party
origins. It breaks this down by both total bytes and the number of requests:&lt;/p&gt;
&lt;img alt=&quot;content breakdown by domain (first view). Shows the percentage of requests and bytes for each third-party&quot; decoding=&quot;async&quot; height=&quot;456&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xl16aV7c9rVOd28JwC70.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;When you see a problematic script, figure out what the script does and ask
yourself whether the script is really that necessary. Do an A/B test to balance
the perceived value versus its impact on key user engagement or performance
metrics.&lt;/p&gt;
&lt;h2 id=&quot;how-do-i-measure-the-impact-of-third-party-script-on-my-page&quot;&gt;How do I measure the impact of third-party script on my page? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#how-do-i-measure-the-impact-of-third-party-script-on-my-page&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;lighthouse-boot-up-time-audit&quot;&gt;Lighthouse Boot-up Time Audit &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#lighthouse-boot-up-time-audit&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Lighthouse &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/bootup-time/&quot; rel=&quot;noopener&quot;&gt;JavaScript boot-up time audit&lt;/a&gt; highlights scripts that have a
costly script parse, compile or evaluation time. This can be useful for
discovering CPU-intensive third-party scripts.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse showing support for script evaluating and parsing&quot; decoding=&quot;async&quot; height=&quot;523&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/MigUKr6en9egqep32LmP.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;lighthouse-network-payloads-audit&quot;&gt;Lighthouse Network Payloads Audit &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#lighthouse-network-payloads-audit&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Lighthouse &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/total-byte-weight/&quot; rel=&quot;noopener&quot;&gt;Network Payloads audit&lt;/a&gt; identifies network
requests (including those from third-parties) that may slow down page load time.
Avoiding these requests or highlighting their cost to ad-networks can save users
money they would have spent on cellular data.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse showing support for large network payloads&quot; decoding=&quot;async&quot; height=&quot;477&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5l7yuCUvUgE0zdRGBZAV.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;chrome-devtools-network-request-blocking&quot;&gt;Chrome DevTools Network Request Blocking &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#chrome-devtools-network-request-blocking&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Chrome DevTools allows you to see how your page behaves when a particular
script, stylesheet or other resource isn’t available. This is done with &lt;a href=&quot;https://developer.chrome.com/blog/new-in-devtools-59/#block-requests&quot; rel=&quot;noopener&quot;&gt;network request blocking&lt;/a&gt;, a
feature that can help measure the impact of blocking (dropping) specific
third-party resources from your page.&lt;/p&gt;
&lt;p&gt;To enable request blocking, right click on any request in the Network panel and
select &amp;quot;Block Request URL&amp;quot;. A Request blocking tab will display in the DevTools
drawer, letting you manage which requests have been blocked.&lt;/p&gt;
&lt;img alt=&quot;Block request URLs from the DevTools network panel&quot; decoding=&quot;async&quot; height=&quot;392&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/LnMJijjS4i9GYaYitEzK.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;chrome-devtools-performance-panel&quot;&gt;Chrome DevTools Performance Panel &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#chrome-devtools-performance-panel&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/devtools/performance/reference/&quot; rel=&quot;noopener&quot;&gt;Performance panel&lt;/a&gt; in Chrome
DevTools helps identify issues with your page’s web performance. Clicking the
record button and loading your page presents you with a waterfall representing
where your site is spending time. At the bottom of the Performance panel, you
will see a drawer starting with
&amp;quot;&lt;a href=&quot;https://developer.chrome.com/docs/devtools/performance/reference/#record-load&quot; rel=&quot;noopener&quot;&gt;Summary&lt;/a&gt;&amp;quot;.
Navigate to the “Bottom-up” tab.&lt;/p&gt;
&lt;p&gt;Here, you can use the &amp;quot;Group by product&amp;quot; option in the Bottom-Up tab to group
third-parties by the time they spent. This helps identify which third-party
products were the most costly. The &lt;a href=&quot;https://umaar.com/dev-tips/143-network-products/&quot; rel=&quot;noopener&quot;&gt;Network panel&lt;/a&gt; also supports an option
to highlight requests by product.&lt;/p&gt;
&lt;img alt=&quot;DevTools Performance panel showing the Bottom-up view grouped by (third-party) products&quot; decoding=&quot;async&quot; height=&quot;744&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/Mfa08JHyo9TFo6zGgzci.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To learn more about how to analyze page load performance with the Chrome
DevTools, see &lt;a href=&quot;https://developer.chrome.com/docs/devtools/performance/&quot; rel=&quot;noopener&quot;&gt;Get started with analyzing runtime performance&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A good &lt;strong&gt;workflow&lt;/strong&gt; for measuring the impact of third-party scripts is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Measure how long it takes to load your page using the Network panel.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To emulate real-world conditions, we recommend turning on &lt;a href=&quot;https://developer.chrome.com/docs/devtools/network/reference/#throttling&quot; rel=&quot;noopener&quot;&gt;network throttling&lt;/a&gt; and
&lt;a href=&quot;https://developer.chrome.com/docs/devtools/device-mode/#cpu&quot; rel=&quot;noopener&quot;&gt;CPU throttling&lt;/a&gt;.
On faster connections and desktop hardware, the impact of expensive
scripts may not be as representative as it would on a mobile phone.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Block the URLs or domains responsible for third-party scripts you believe are
an issue (see &lt;em&gt;Chrome DevTools Performance Panel&lt;/em&gt; for identifying costly
scripts).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reload the page and re-measure how long the page takes without loading these
blocked third-party scripts. You should hopefully see an improvement.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There may be value in doing 3 or more runs of measurement and looking at
the median for more stable figures. As third-party content can
occasionally pull in different resources per page load, this could give
you a more realistic spread. &lt;a href=&quot;https://twitter.com/ChromeDevTools/status/963820146388221952&quot; rel=&quot;noopener&quot;&gt;DevTools now supports multiple recordings&lt;/a&gt;
in the performance panel, making this a little easier.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;measuring-impact-of-third-party-tags-with-webpagetest&quot;&gt;Measuring impact of Third-Party tags with WebPageTest &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#measuring-impact-of-third-party-tags-with-webpagetest&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.webpagetest.org/&quot; rel=&quot;noopener&quot;&gt;WebPageTest&lt;/a&gt; supports blocking individual
requests from loading (which can be useful for blocking content like ads and
third-party embeds) to measure their impact.&lt;/p&gt;
&lt;p&gt;Under &amp;quot;Advanced Settings&amp;quot; is a Block tab. This can be used to specify a list of
domains to block, simulating what it would be like if they didn&#39;t load at all.&lt;/p&gt;
&lt;img alt=&quot;WebPageTest advanced settings &amp;amp;lt; Block. Displays a text area for specifying domains to block.&quot; decoding=&quot;async&quot; height=&quot;316&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/HBkSyajyxG7vxfPsyPKI.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;A workflow for using this feature is to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Test a page as normal&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repeat the test with certain third-parties blocked&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compare the two results (paying attention to the filmstrip). Results can be
compared by selecting them from your &lt;a href=&quot;https://www.webpagetest.org/testlog/1/&quot; rel=&quot;noopener&quot;&gt;Test History&lt;/a&gt; and clicking ‘Compare’.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;WebPageTest displaying the compare option allowing you to compare two reports&quot; decoding=&quot;async&quot; height=&quot;245&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/t56zbdtSDZJlPjQzz4rm.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Below we can see the difference between filmstrips both with and without
third-party resources blocked. It can be useful to try this out for individual
third-party origins to determine which ones have the biggest impact on your
page-load performance:&lt;/p&gt;
&lt;img alt=&quot;WebPageTest filmstrip displaying the impact of loading a site with and without third-parties disabled&quot; decoding=&quot;async&quot; height=&quot;139&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/GilGzoBGdzQysYvhMNkH.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The impact of blocking third-party resources on a page using WPT’s &amp;quot;block
requests&amp;quot; feature from “&lt;a href=&quot;https://goo.gl/jwGg6X&quot; rel=&quot;noopener&quot;&gt;Using WebPageTest To Measure The Impact Of Third-Party Tags&lt;/a&gt;” by Andy Davies&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; WebPageTest also supports two commands operating at the DNS level for blocking domains. &lt;a href=&quot;https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/scripting#TOC-blockDomains&quot;&gt;blockDomains&lt;/a&gt; &lt;/div&gt;&lt;/aside&gt;
&lt;ul&gt;
&lt;li&gt;which takes a list of domains to block and
&lt;a href=&quot;https://sites.google.com/a/webpagetest.org/docs/using-webpagetest/scripting#TOC-blockDomainsExcept&quot; rel=&quot;noopener&quot;&gt;blockDomainsExcept&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;takes a list of domains and blocks anything not on the list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WebPageTest also has a single-point of failure (SPOF) tab. This allows you to
simulate a timeout or complete failure to load a resource.&lt;/p&gt;
&lt;p&gt;The difference between &amp;quot;SPOF&amp;quot; and &amp;quot;Block&amp;quot; is that SPOF slowly times out. This
can make it useful for testing network resilience of third-party content to
determine how well your pages hold up when services are under heavy load or
temporarily unavailable.&lt;/p&gt;
&lt;img alt=&quot;WebPageTest advanced settings &amp;amp;gt; SPOF &amp;amp;gt; hosts to fail&quot; decoding=&quot;async&quot; height=&quot;346&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/ZUkUg3FkHz1cyrPVbqkn.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;detecting-expensive-iframes-using-long-tasks&quot;&gt;Detecting expensive iframes using Long Tasks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#detecting-expensive-iframes-using-long-tasks&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When scripts in third-party iframes take a long time to run, they can block the
main thread delaying other tasks from running. These long tasks can cause a
negative user experience leading to sluggish event handlers or dropped frames.&lt;/p&gt;
&lt;p&gt;To detect long tasks for &lt;a href=&quot;https://en.wikipedia.org/wiki/Real_user_monitoring&quot; rel=&quot;noopener&quot;&gt;Real User Monitoring&lt;/a&gt; (RUM), we can
use the JavaScript
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/PerformanceObserver&quot; rel=&quot;noopener&quot;&gt;PerformanceObserver&lt;/a&gt;
API and observe
&lt;a href=&quot;https://web.dev/user-centric-performance-metrics/#custom-metrics&quot;&gt;longtask&lt;/a&gt;
entries. As these entries contain an attribution property, we can track down
which frame context was responsible for the task.&lt;/p&gt;
&lt;p&gt;Below is an example that will log &lt;code&gt;longtask&lt;/code&gt; entries to the console, including
one for an &amp;quot;expensive&amp;quot; iframe:&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 keyword&quot;&gt;const&lt;/span&gt; observer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PerformanceObserver&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 parameter&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&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;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; entry &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; list&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getEntries&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;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Attribution entry including &quot;containerSrc&quot;:&quot;https://example.com&quot;&lt;/span&gt;&lt;br /&gt;      console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;attribution&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 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;br /&gt;  observer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;observe&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 literal-property property&quot;&gt;entryTypes&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;&#39;longtask&#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;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 comment&quot;&gt;&amp;lt;!-- Imagine this is an iframe with expensive long tasks --&gt;&lt;/span&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;iframe&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://example.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&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;iframe&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;To learn more about monitoring Long Tasks, read Phil Walton’s &lt;a href=&quot;https://web.dev/user-centric-performance-metrics/#custom-metrics&quot;&gt;User-centric Performance Metrics&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-load-third-party-script-efficiently&quot;&gt;How do you load third-party script efficiently? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#how-do-you-load-third-party-script-efficiently&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If a third-party script is slowing down your page load, you have several options
to improve performance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Load the script using the async or defer attribute to avoid blocking document
parsing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider self-hosting the script if the third-party server is slow.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider removing the script if it doesn&#39;t add clear value to your site.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/&quot; rel=&quot;noopener&quot;&gt;Resource Hints&lt;/a&gt; like
&lt;code&gt;&amp;lt;link rel=preconnect&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;link rel=dns-prefetch&amp;gt;&lt;/code&gt; to perform a DNS lookup
for domains hosting third-party scripts.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;use-async-or-defer&quot;&gt;Use async or defer &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#use-async-or-defer&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;JavaScript execution is parser blocking. This means when the browser encounters
a script it must pause DOM construction, hand this over to the JavaScript engine
and allow script execution before proceeding with DOM construction.&lt;/p&gt;
&lt;p&gt;The async and defer attributes change this behavior.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;With async, the browser downloads the script asynchronously while it continues
to parse the HTML document. When the script finishes downloading, parsing is
blocked while the script executes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;With defer, the browser downloads the script asynchronously while it continues
to parse the HTML document. The script doesn&#39;t run until the parsing is
complete.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If that&#39;s too many words, here&#39;s a pretty picture:&lt;/p&gt;
&lt;img alt=&quot;A visualization comparing the impact of using script vs script async vs script defer. Defer is showing as executing after script fetch and HTML parsing is done.&quot; decoding=&quot;async&quot; height=&quot;447&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/AiNx4BNv1tSLpz83EAmZ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;&lt;em&gt;Credit: Growing with the web&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In general, you should always use &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt; for third-party scripts
(unless the script does something necessary for the critical rendering path):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;async&lt;/code&gt; if it&#39;s important to have the script run earlier in the loading
process. This might include some analytics scripts, for example.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;code&gt;defer&lt;/code&gt; for less critical resources. A video player that&#39;s below-the-fold,
for example.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; If performance is your primary concern, you could wait until your page has reached a key user moment (such as after the critical content has loaded) before adding async scripts. You should also take care not to &lt;code&gt;async&lt;/code&gt; load libraries like jQuery just because they are coming from a third-party CDN. &lt;/div&gt;&lt;/aside&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; In Blink-based browsers, &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;defer&lt;/code&gt; currently &lt;a href=&quot;https://docs.google.com/document/d/1bCDuq9H1ih9iNjgzyAL0gpwNFiEP4TZS-YLRp_RuMlc/edit#&quot;&gt;lower the priority of the network request&lt;/a&gt; for resources so it can cause it to load significantly later than it would as a blocking script. This is useful to know in particular for analytics scripts. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Should you ever load third-party scripts without &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt;? You could
make a case for this if the script is a crucial part of your site functionality.
For example, if you&#39;re loading your main UI library or framework from a CDN, it
will be badged as &amp;quot;third-party script&amp;quot; in DevTools, but should be treated as an
essential part of your site, not an add-on.&lt;/p&gt;
&lt;p&gt;Note that not all scripts work if loaded asynchronously. Check the docs for any
third-party scripts you&#39;re using. If you&#39;re using a script that can&#39;t be loaded
asynchronously, you might want to consider an alternative, or eliminating the
script if possible. Some third parties may &lt;em&gt;highly recommend&lt;/em&gt; to load their
scripts sync (to get ahead of other scripts), even if they would work fine async
so do due diligence when evaluating strategies for loading third-party scripts.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; &lt;code&gt;async&lt;/code&gt; is not a silver bullet. If a marketing team wants to load a large number of tracking scripts on a page, this number will still introduce bottlenecks that can impact how soon users can engage with a page on load. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;use-resource-hints-to-reduce-connection-setup-time&quot;&gt;Use Resource Hints to reduce connection setup time &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#use-resource-hints-to-reduce-connection-setup-time&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Establishing connections to third-party origins can take a significant amount of
time - particularly on slow networks. Many steps can add up to delays including
DNS lookups, redirects, and potentially several round trips to each third-party
server to handle the request.&lt;/p&gt;
&lt;p&gt;You can use &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/&quot; rel=&quot;noopener&quot;&gt;Resource Hints&lt;/a&gt; like
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/#improve-page-load-speed-with-preconnect&quot; rel=&quot;noopener&quot;&gt;&lt;link rel=&quot;dns-prefetch&quot; /&gt;&lt;/a&gt;
to perform a DNS lookup for domains hosting third-party scripts. When the
request for them is finally made, time can be saved as the DNS lookup has
already been carried out.&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;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;dns-prefetch&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://example.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;If the third-party domain you are referencing uses HTTPS, you may also consider
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/&quot; rel=&quot;noopener&quot;&gt;&lt;link rel=&quot;preconnect&quot; /&gt;&lt;/a&gt;
as this will both perform the DNS lookup &lt;em&gt;and&lt;/em&gt; resolve TCP round-trips and
handle TLS negotiations. These other steps can be very slow as they involve
looking at SSL certificates for verification, so consider Resource Hints
seriously if you find third-party setup time to be an issue.&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;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preconnect&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://cdn.example.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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;h3 id=&quot;sandbox-scripts-with-an-iframe&quot;&gt;&amp;quot;Sandbox&amp;quot; scripts with an iframe &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#sandbox-scripts-with-an-iframe&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are cases where third-party scripts can be loaded directly into an iframe.
By restricting such scripts to iframes, they won’t block execution of the main
page. This is the same approach that
&lt;a href=&quot;https://www.ampproject.org/learn/about-how/&quot; rel=&quot;noopener&quot;&gt;AMP&lt;/a&gt; takes to keeping JavaScript
out of the &lt;a href=&quot;https://web.dev/critical-rendering-path/&quot;&gt;critical path&lt;/a&gt;. Note that this
approach will still block the &lt;code&gt;onload&lt;/code&gt; event so try not to attach critical
functionality to &lt;code&gt;onload&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Chrome also supports &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Permissions_Policy&quot; rel=&quot;noopener&quot;&gt;Permissions Policy&lt;/a&gt;
(formerly Feature Policy) - a set of policies which allow a developer to selectively disable access to certain browser
features. This can prevent third-party content introducing unwanted behaviors to a site.&lt;/p&gt;
&lt;h3 id=&quot;self-host-third-party-scripts&quot;&gt;Self-host third-party scripts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#self-host-third-party-scripts&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Self-hosting third-party scripts may be an option if you would like more control
over a script’s loading story. For example, if you wanted to reduce DNS or
round-trip times, or improve HTTP caching headers. Self-hosting may be a viable
consideration if a script is considered critical.&lt;/p&gt;
&lt;p&gt;Self-hosting can come with a number of big caveats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Scripts can go out of date. This can be a large issue as it prevents you from
getting important security fixes without manually updating.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scripts that are self-hosted won’t get automatic updates due to an API change.
One example: a publisher with 90% of their revenue from ads discovers that ads
didn’t serve for half a day due to an API change that their self-hosted script
didn’t account for, leading to loss in income.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An alternative to self-hosting scripts would be using &lt;a href=&quot;https://developer.chrome.com/docs/workbox/service-worker-overview/&quot; rel=&quot;noopener&quot;&gt;Service Workers&lt;/a&gt; to cache them. This can
give you greater control over how often they are re-fetched from the network.
This could also be used to create a loading strategy where requests for
non-essential third parties are throttled until the page reaches a key user
moment.&lt;/p&gt;
&lt;h3 id=&quot;ab-test-smaller-samples-of-users&quot;&gt;A/B Test smaller samples of users &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#ab-test-smaller-samples-of-users&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.optimizely.com/optimization-glossary/ab-testing/&quot; rel=&quot;noopener&quot;&gt;A/B testing&lt;/a&gt; (or
split-testing) is a technique for experimenting with two versions of a page to
determine which one performs best. This is done by enabling both variants (A and
B) for different samples of your website traffic. The page that provides a
better conversion rate wins.&lt;/p&gt;
&lt;p&gt;A/B testing is a very useful tool for analyzing user experience and behavior.&lt;/p&gt;
&lt;p&gt;However, by design, A/B testing delays rendering to figure out which experiment
needs to be active. JavaScript is often used to check if any of your users
belong to an A/B test experiment and then enable the correct variant. This
pattern can lead to 100% of your users being sent down large, costly script even
if they don’t belong to the sample receiving the experiment.&lt;/p&gt;
&lt;p&gt;A good alternative in this case is to send A/B testing scripts for only a subset
of your user base (e.g 10% vs 100%), ideally attempting to decide whether they
belong in a test sample on the server-side. This improves the loading experience
for the majority of users while still making split-testing possible.&lt;/p&gt;
&lt;h3 id=&quot;lazy-load-third-party-resources&quot;&gt;Lazy load Third-Party Resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#lazy-load-third-party-resources&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Embedded third-party resources (such as ads or videos) can be a big contributor
to slow page speed when constructed poorly. Lazy loading can be used to only
load embedded resources when necessary. For example, serving an ad in the footer
only when a user scrolls down the page. Another pattern is lazy loading content
after the main page content loads but before a user might otherwise interact
with the page.&lt;/p&gt;
&lt;img alt=&quot;An illustration showing assets that are critical for the above the fold experience and those that are less critical and can be lazily loaded in.&quot; decoding=&quot;async&quot; height=&quot;340&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 767px) 767px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/5Iag22tSQLyGshoHkuqk.png?auto=format&amp;w=1534 1534w&quot; width=&quot;767&quot; /&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; &lt;a href=&quot;https://github.com/aFarkas/lazysizes&quot;&gt;LazySizes&lt;/a&gt; is a popular JavaScript library for lazy loading images and&lt;a href=&quot;http://afarkas.github.io/lazysizes/#examples&quot;&gt;iframes&lt;/a&gt;. It supports YouTube embeds and&lt;a href=&quot;https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/unveilhooks&quot;&gt;widgets&lt;/a&gt;. Care does need to be taken when lazy loading any resources as this technique is often powered by JavaScript and can be subject to issues on flaky network connections. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;DoubleClick have guidance on how to lazy-load ads in their &lt;a href=&quot;https://support.google.com/dfp_premium/answer/4578089#lazyloading&quot; rel=&quot;noopener&quot;&gt;official documentation&lt;/a&gt;.
If used properly, lazy loading can increase the overall viewability percentage
of an ad. For example, Mediavine switched to&lt;a href=&quot;https://www.mediavine.com/lazy-loading-ads-mediavine-ads-load-200-faster/&quot; rel=&quot;noopener&quot;&gt;lazy-loading ads&lt;/a&gt;
and saw a 200% improvement in page load speed.&lt;/p&gt;
&lt;h4 id=&quot;efficient-lazy-loading-with-intersection-observer&quot;&gt;Efficient lazy loading with Intersection Observer &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#efficient-lazy-loading-with-intersection-observer&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Historically, solutions for detecting if an element is visible in the viewport
(in order to lazy-load its content) have been error-prone, often causing the
browser to become sluggish. Solutions have often listened for
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Events/scroll&quot; rel=&quot;noopener&quot;&gt;scroll&lt;/a&gt; or
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Events/resize&quot; rel=&quot;noopener&quot;&gt;resize&lt;/a&gt; events,
then used DOM APIs like
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Element/getBoundingClientRect&quot; rel=&quot;noopener&quot;&gt;getBoundingClientRect()&lt;/a&gt;
to calculate where elements are relative to the viewport. This works, but is not
efficient.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/intersectionobserver-v2/&quot;&gt;IntersectionObserver&lt;/a&gt; is a browser
API that allows us to efficiently detect when an observed element enters or
exits the browser&#39;s viewport. Learn more about how to use it for &lt;a href=&quot;https://deanhume.com/home/blogpost/lazy-loading-images-using-intersection-observer/10163&quot; rel=&quot;noopener&quot;&gt;lazy loading resources&lt;/a&gt;.
LazySizes also has&lt;a href=&quot;https://github.com/aFarkas/lazysizes/blob/097a9878817dd17be3366633e555f3929a7eaaf1/src/lazysizes-intersection.js&quot; rel=&quot;noopener&quot;&gt;optional support&lt;/a&gt;
for IntersectionObserver.&lt;/p&gt;
&lt;h3 id=&quot;analytics-can-be-complicated&quot;&gt;Analytics can be complicated &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#analytics-can-be-complicated&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Analytics scripts should never slow down your page load experience, but if you
defer the load too long you can miss valuable analytics data. Fortunately, there
are some well-known patterns for initializing analytics lazily while retaining
early page-load data.&lt;/p&gt;
&lt;p&gt;Phil Walton&#39;s blog post, &lt;a href=&quot;https://philipwalton.com/articles/the-google-analytics-setup-i-use-on-every-site-i-build/&quot; rel=&quot;noopener&quot;&gt;The Google Analytics Setup I Use on Every Site I Build&lt;/a&gt;
covers one such pattern for Google Analytics.&lt;/p&gt;
&lt;h2 id=&quot;what-patterns-should-i-avoid-with-third-party-script&quot;&gt;What patterns should I avoid with third-party script? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#what-patterns-should-i-avoid-with-third-party-script&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;avoid-documentwrite&quot;&gt;Avoid document.write() &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#avoid-documentwrite&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Third-party scripts sometimes use
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Document/write&quot; rel=&quot;noopener&quot;&gt;document.write()&lt;/a&gt;
to inject and load scripts. This is particularly true of older services that
haven’t been updated in some time. Thankfully, many third-parties offer an
option to asynchronously load themselves, which allows third-party scripts to
load without blocking the display of the rest of the content on the page.&lt;/p&gt;
&lt;p&gt;The fix for document.write() is to simply not inject scripts using it. As of
Chrome 53, Chrome DevTools will log warnings to the console for problematic use
of document.write():&lt;/p&gt;
&lt;img alt=&quot;DevTools console warnings highlighting violations for a third-party embed using document.write()&quot; decoding=&quot;async&quot; height=&quot;500&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/4xJzx0Of1N7sTqHRJyyG.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To discover the use of document.write() at scale, you can check for &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers&quot; rel=&quot;noopener&quot;&gt;HTTP headers&lt;/a&gt; sent to your
browser when this intervention for Chrome happens.
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse&lt;/a&gt; can also highlight any third-party scripts
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/best-practices/no-document-write/&quot; rel=&quot;noopener&quot;&gt;still using document.write()&lt;/a&gt; in
the Lighthouse report:&lt;/p&gt;
&lt;img alt=&quot;Lighthouse Best Practices audit flagging use of document.write()&quot; decoding=&quot;async&quot; height=&quot;438&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/C47gYyWYVMMhDmtYSLOWazuyePF2/xTS1pwZlgoFjnmM7BTBf.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;use-tag-managers-but-use-them-wisely&quot;&gt;Use Tag Managers but use them wisely &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#use-tag-managers-but-use-them-wisely&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Exercise caution when using GTM. Although it can minimize the overhead of third-party tags, it also makes it trivial for anyone with credentials to add costly tags. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;A &amp;quot;tag&amp;quot; is a snippet of code that allows digital marketing teams to collect
data, set cookies or integrate third-party content like social media widgets
into a site. These tags have a cost to your page&#39;s loading performance -
additional network requests, heavy JavaScript dependencies, images and resources
the tag itself may pull in.&lt;/p&gt;
&lt;p&gt;Managing these tags can become a real mess over time as marketing teams wish to
add more ways to understand users and engineering tries to minimize the impact
tags can have on user experience. To keep experiences fast, we recommend using a
Tag manager. Tag managers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;allow many pieces of third-party embed code to be managed from a single place
(usually a user-interface)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;attempt to minimize how much third-party tags need to be deployed to sites.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Even though individual tags can be asynchronously loaded, they still need to be read and executed individually. This could mean requesting more data while the page is still loading. Tag managers address this by reducing the number of calls a browser needs to make for them down to one. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;a href=&quot;https://www.google.com/analytics/tag-manager/&quot; rel=&quot;noopener&quot;&gt;Google Tag Manager&lt;/a&gt; (GTM) is one
such popular tag manager:&lt;/p&gt;
&lt;p&gt;&amp;quot;Google Tag Manager is an asynchronous tag, meaning that when it executes, it
does not block other elements from rendering on the page. It also causes the
other tags that are deployed via Google Tag Manager to be deployed
asynchronously, meaning that a slow loading tag won’t block other tracking
tags.&amp;quot;&lt;/p&gt;
&lt;p&gt;Tag managers may improve page load performance by reducing how many calls to
external resources are needed - as long as you &lt;strong&gt;are not&lt;/strong&gt; pulling in a large
number of tags. They also allow tags a way to collect values in a single unique
place. For GTM, this is the &lt;a href=&quot;https://developers.google.com/tag-platform/tag-manager/web/datalayer&quot; rel=&quot;noopener&quot;&gt;Data Layer&lt;/a&gt;. If multiple
third parties wish to trigger conversion-tracking data, they can do this by
pulling from the Data Layer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Risks when using Tag managers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When using a tag manager, great care needs to be taken to avoid slowing down how
quickly pages load. This is because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Anyone with credentials and access can easily add not just more tags, but
&lt;em&gt;any&lt;/em&gt; JavaScript they want. Although tag managers can load tags
asynchronously, this can still lead to an excess of costly HTTP requests being
made and executed. This can be minimized by only allowing one user to publish
versions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Anyone can configure too many tag manager &lt;a href=&quot;https://support.google.com/analytics/answer/6164470&quot; rel=&quot;noopener&quot;&gt;auto-event listeners&lt;/a&gt;. Every
auto-event listener needs to be executed &amp;amp; the more code and network requests
there are, the longer it can take for a page to fully load. With our
performance guidance encouraging that you &lt;a href=&quot;https://web.dev/rail/&quot;&gt;respond to events within 50ms&lt;/a&gt;, every tag manager event listener
added eats away at that goal.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;avoid-scripts-that-pollute-the-global-scope&quot;&gt;Avoid scripts that pollute the global scope &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#avoid-scripts-that-pollute-the-global-scope&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Third-party scripts injected into the unknown can sometimes load a number of
their own JavaScript dependencies. This can pollute the global scope and cause
accidental breakage in pages.&lt;/p&gt;
&lt;p&gt;There is also no guarantee that code loaded from a third-party will remain the
same as what you saw during testing. New features can be pushed out by third
parties at any time, potentially breaking your page. Self-testing, &lt;a href=&quot;https://developer.mozilla.org/docs/Web/Security/Subresource_Integrity&quot; rel=&quot;noopener&quot;&gt;sub-resource integrity&lt;/a&gt;
and securely transmitting third-party code (to reduce the risk of in-transit
modifications) can help here.&lt;/p&gt;
&lt;p&gt;Be sure to conduct careful audits of the third-party scripts you load to ensure
they’re being good actors.&lt;/p&gt;
&lt;h2 id=&quot;mitigation-strategies&quot;&gt;Mitigation strategies &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#mitigation-strategies&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Adding third-party scripts to a page implies a level of trust in the origin.
There are some strategies you can take to minimize their impact on performance
and security:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://web.dev/why-https-matters/&quot;&gt;HTTPS&lt;/a&gt;&lt;/strong&gt; is a
must. Sites working over HTTPS shouldn’t have third-parties working over HTTP.
An HTTPS page that includes content fetched using HTTP is called a mixed
content page and will run into &lt;a href=&quot;https://developer.mozilla.org/docs/Web/Security/Mixed_content&quot; rel=&quot;noopener&quot;&gt;Mixed Content&lt;/a&gt;
warnings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider the &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/HTML/Element/iframe&quot; rel=&quot;noopener&quot;&gt;sandbox attribute&lt;/a&gt;&lt;/strong&gt; on
iframes. From a security perspective, this allows you to restrict the actions
available from the iframe. Restrictions include &lt;code&gt;allow-scripts&lt;/code&gt;controlling
whether the context can run scripts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider &lt;strong&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/CSP&quot; rel=&quot;noopener&quot;&gt;Content Security Policy&lt;/a&gt;&lt;/strong&gt; (CSP).
Through a HTTP header in your server’s response, you can define behaviors that
are trusted in the page. CSP can be used to detect and mitigate against the
effects of certain attacks, such as &lt;a href=&quot;https://en.wikipedia.org/wiki/Cross-site_scripting&quot; rel=&quot;noopener&quot;&gt;Cross Site Scripting&lt;/a&gt; (XSS).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CSP is particularly powerful as it includes directives such as
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/script-src&quot; rel=&quot;noopener&quot;&gt;script-src&lt;/a&gt;
that specifies what are valid, allowed sources for JavaScript. Below is an
example of how this can be used in practice:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;// Given this CSP header Content-Security-Policy: script-src&lt;br /&gt;https://example.com/ // The following third-party script will not be loaded or&lt;br /&gt;executed&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://not-example.com/js/library.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With sites relying on more third-party scripts than ever, it’s paramount not to
ignore third-party script performance. Good things you can do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Become familiar with some of the most effective third-party script
optimization methods like only loading tags that support the async loading
pattern.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Understand how to identify and fix issues with third-party script loading.
This can help you take back control of your page load performance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Third-party script optimization should be followed by on-going real-time
performance monitoring of your scripts and communication with your third-party
providers. The web is evolving at a rapid pace and a script’s locally observed
performance gives no guarantees that it will perform as well in the future or in
the wild.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot;&gt;Further reading &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimizing-content-efficiency-loading-third-party-javascript/#further-reading&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://csswizardry.com/2017/07/performance-and-resilience-stress-testing-third-parties/&quot; rel=&quot;noopener&quot;&gt;Performance and Resilience: Stress-Testing Third Parties&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/critical-rendering-path-adding-interactivity-with-javascript/&quot;&gt;Adding interactivity with JavaScript&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://css-tricks.com/potential-dangers-of-third-party-javascript/&quot; rel=&quot;noopener&quot;&gt;Potential dangers with Third-party Scripts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.twnsnd.com/posts/performant_third_party_scripts.html&quot; rel=&quot;noopener&quot;&gt;How 3rd Party Scripts can be performant citizens on the web&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://speakerdeck.com/csswizardry/why-fast-matters&quot; rel=&quot;noopener&quot;&gt;Why Fast Matters - CSS Wizardry&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.troyhunt.com/the-javascript-supply-chain-paradox-sri-csp-and-trust-in-third-party-libraries/&quot; rel=&quot;noopener&quot;&gt;The JavaScript Supply Chain Paradox: SRI, CSP and Trust in Third Party Libraries&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jakearchibald.com/2018/third-party-css-is-not-safe/&quot; rel=&quot;noopener&quot;&gt;Third-party CSS isn&#39;t safe&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;With thanks to Kenji Baheux, Jeremy Wagner, Pat Meenan, Philip Walton, Jeff
Posnick and Cheney Tsai for their reviews.&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Arthur Evans</name>
    </author>
  </entry>
</feed>
