<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Chris Haynes</title>
    <description>The latest articles on Forem by Chris Haynes (@lamplightdev).</description>
    <link>https://forem.com/lamplightdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F145556%2F33721dde-4728-4e74-8d7f-fed7040f4570.jpeg</url>
      <title>Forem: Chris Haynes</title>
      <link>https://forem.com/lamplightdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lamplightdev"/>
    <language>en</language>
    <item>
      <title>How to detect clicks outside of a Web Component</title>
      <dc:creator>Chris Haynes</dc:creator>
      <pubDate>Sat, 10 Apr 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/lamplightdev/how-to-detect-clicks-outside-of-a-web-component-4cll</link>
      <guid>https://forem.com/lamplightdev/how-to-detect-clicks-outside-of-a-web-component-4cll</guid>
      <description>&lt;p&gt;When using Web Components it's often necessary to be able to distinguish between clicks inside the component from those outside of it.&lt;/p&gt;

&lt;p&gt;For example you may want to show some content when a button is clicked, and then hide it when the user clicks outside the component but not when the user clicks inside the component:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CByHQd7T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://lamplightdev.com/images/2021-04-10-1-7226e174.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CByHQd7T--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://lamplightdev.com/images/2021-04-10-1-7226e174.gif" alt="Screencast showing a button opening a component, clicking of buttons inside the component that do not close it, and a click outside the component which does close it"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;What may seem a simple problem becomes more complicated when you consider how events are treated differently depending on whether an element is in the Shadow DOM or in the Light DOM.&lt;/p&gt;

&lt;p&gt;Take the following component definition used in the above example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-component&amp;gt;&lt;/span&gt;
  #shadow-root
    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Open&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Button A&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;slot&amp;gt;&amp;lt;slot&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;Button B&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The desired behaviour is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;close when you click outside the component&lt;/li&gt;
&lt;li&gt;do not close when the component itself is clicked&lt;/li&gt;
&lt;li&gt;do not close when an element in the Shadow DOM is clicked (Button A)&lt;/li&gt;
&lt;li&gt;do not close when an element in the Light DOM is clicked (Button B)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A first attempt may be to add an event listener defined inside your component like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;✅ For a click outside the component &lt;code&gt;event.target !== this&lt;/code&gt; so the component will close.&lt;/li&gt;
&lt;li&gt;✅ For a click on the component itself &lt;code&gt;event.target === this&lt;/code&gt; so the component will not close.&lt;/li&gt;
&lt;li&gt;✅ For a click on Button A inside the Shadow DOM,&lt;code&gt;event.target === this&lt;/code&gt; so the component will not close.&lt;/li&gt;
&lt;li&gt;❌ For a click on Button B inside the Light DOM &lt;code&gt;event.target !== this&lt;/code&gt; so the component will close.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But why is &lt;code&gt;event.target === this&lt;/code&gt; for elements inside the Shadow DOM, but not for elements inside the Light DOM?&lt;/p&gt;

&lt;h2&gt;
  
  
  Event retargeting
&lt;/h2&gt;

&lt;p&gt;For elements inside the Shadow DOM events are automatically &lt;strong&gt;retargeted&lt;/strong&gt; to the parent component. This means that &lt;code&gt;event.target&lt;/code&gt; is set to the parent component for any event originating from inside the Shadow DOM.&lt;/p&gt;

&lt;p&gt;But for elements in the Light DOM, which are only &lt;strong&gt;projected&lt;/strong&gt; to the inside of a component and are not physically moved there, the &lt;code&gt;event.target&lt;/code&gt; remains set to the element itself.&lt;/p&gt;

&lt;p&gt;So how do you find out if an element in a component's Light DOM was clicked?&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;event.composedPath()&lt;/code&gt; method shows you each element the event passed through from the originating element right up to the &lt;code&gt;Window&lt;/code&gt; object at the top of the DOM tree. This works on the &lt;strong&gt;projected DOM tree&lt;/strong&gt; so that the elements are included in the order that they appear when rendered rather than their physical position in the DOM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;composedPath&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="cm"&gt;/*
    this will log an array containing the following
    when a button in the Shadow DOM is clicked:

    0: button.A
    1: div#container
    2: document-fragment
    3: my-component &amp;lt;--
    4: body
    5: html
    6: document
    7: Window

    and the following when a button in the Light DOM is clicked:

    0: button.B
    1: slot
    2: div#container
    3: document-fragment
    4: my-component &amp;lt;--
    5: body
    6: html
    7: document
    8: Window
  */&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both cases you can see that &lt;code&gt;my-component&lt;/code&gt; appears in the composed path. Using this fact you can update the event listener to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;composedPath&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;✅ For a click outside the component &lt;code&gt;composedPath()&lt;/code&gt; will not include the component (&lt;code&gt;this&lt;/code&gt;) so the component will close.&lt;/li&gt;
&lt;li&gt;✅ For a click on the component itself &lt;code&gt;composedPath()&lt;/code&gt; will include &lt;code&gt;this&lt;/code&gt; so the component will not close.&lt;/li&gt;
&lt;li&gt;✅ For a click on Button A inside the Shadow DOM,&lt;code&gt;composedPath()&lt;/code&gt; will include &lt;code&gt;this&lt;/code&gt; so the component will not close.&lt;/li&gt;
&lt;li&gt;✅ For a click on Button B inside the Light DOM &lt;code&gt;composedPath()&lt;/code&gt; will include &lt;code&gt;this&lt;/code&gt; so the component will not close.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🎆 Bingo, &lt;code&gt;composedPath()&lt;/code&gt; gives you all the information you need to see where the event originated!&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://glitch.com/edit/#!/solar-conscious-bull?path=index.html%3A82%3A68"&gt;view a full code example of the above component here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://eepurl.com/gvjFwv"&gt;Subscribe to my mailing list to be notified of new posts about Web Components and building performant websites&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to share styles in the Shadow DOM</title>
      <dc:creator>Chris Haynes</dc:creator>
      <pubDate>Tue, 23 Mar 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/lamplightdev/how-to-share-styles-in-the-shadow-dom-4ag6</link>
      <guid>https://forem.com/lamplightdev/how-to-share-styles-in-the-shadow-dom-4ag6</guid>
      <description>&lt;p&gt;The Shadow DOM is great for insulating your Web Components from global style rules, but what do you do if you want to share common styling between components? One approach is to duplicate style rules across components but that can be inefficient and a maintenance headache - surely there's another way?&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Let's take a simplified Card component containing a button, and place it on a page also containing a button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyCard&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// these should be sanitized!&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
      &amp;lt;style&amp;gt;
        :host {
          display: flex;
          flex-direction: column;
          border: 1px solid #ddd;
          border-radius: 0.2rem;
        }

        #title {
          display: flex;
          align-items: center;
          justify-content: space-between;
          padding: 1rem;
          font-size: 2rem;
          border-bottom: 1px solid #ddd;
        }

        #content {
          padding: 1rem;
        }
      &amp;lt;/style&amp;gt;

      &amp;lt;div id="title"&amp;gt;
        &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
        &amp;lt;button&amp;gt;I am inside a component, click me!&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;

      &amp;lt;div id="content"&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/div&amp;gt;
      `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyCard&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;I'm not in a component&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;my-card&lt;/span&gt; &lt;span class="na"&gt;my-title=&lt;/span&gt;&lt;span class="s"&gt;"Hello"&lt;/span&gt; &lt;span class="na"&gt;my-content=&lt;/span&gt;&lt;span class="s"&gt;"Welcome to the jungle!"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-card&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which gives us:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DHvBTGCU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lamplightdev.com/images/2021-03-23-before-d5dc279d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DHvBTGCU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lamplightdev.com/images/2021-03-23-before-d5dc279d.png" alt="Unstyled buttons"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The challenge then is how to style the button so that it looks the same both inside and outside of your component. Let's use the following CSS to style your button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;steelblue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C7Wz7ImG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lamplightdev.com/images/2021-03-23-after-24d791e9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C7Wz7ImG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lamplightdev.com/images/2021-03-23-after-24d791e9.png" alt="Unstyled buttons"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where do you put these styles so they apply to the outer page and inside your component?&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The wrong way
&lt;/h2&gt;

&lt;p&gt;The wrong way is to add those styles to your page's stylesheet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/button.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- button.css contains the buttons styles above --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AND in the style block inside your component's Shadow DOM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;/* button styles here */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;/* your component specific styles go here*/&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you may have spotted, this has several limitations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Duplication&lt;/strong&gt; - if you want to change your button styling, you have to update it in your stylesheet and in every component that contains a button.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wasted bytes&lt;/strong&gt; - the browser has to download the same CSS for the outer page and for every component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not dynamic&lt;/strong&gt; - if you want to update the styling dynamically then you are out of luck.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  A better way
&lt;/h2&gt;

&lt;p&gt;Luckily &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tags are valid inside the Shadow DOM as well as in your outer page, so you can use the link from the outer page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/button.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- button.css contains the buttons styles above --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and re-use it in your component's Shadow DOM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;link rel="stylesheet" href="/button.css" /&amp;gt;
  &amp;lt;style&amp;gt;
    /* your component specific styles go here */
  &amp;lt;/style&amp;gt;
  ...
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this way you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Avoid duplication&lt;/strong&gt; - you only have to write your styles once, inside the stylesheet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No wasted bytes&lt;/strong&gt; - as long as the stylesheet is sent with sensible caching headers, only the first time the stylesheet is encountered will it need to be downloaded. Subsequent requests for the stylesheet will come straight from the cache.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that if you only include the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;in your components, and not in the outer page, you risk the dreaded flash of unstyled content (FOUC). This is because &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tags in the ShadowDOM are &lt;strong&gt;not&lt;/strong&gt; render blocking - in other words the browser will display the content of your Shadow DOM before the styles have been downloaded and parsed. By adding the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; to your outer page (where it is render blocking) this will force the browser to download the styles before it attempts to display any content. Then when the browser encounters the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; again inside your component it will already have been cached and ready to apply immediately.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Dynamic styles
&lt;/h2&gt;

&lt;p&gt;But one issue remains with this better approach - if you want to dynamically update the styling of your button there still isn't once place where you can change the style and have it update the style of all your buttons.&lt;/p&gt;

&lt;p&gt;Both the outer page and each of your components are using a copy of the same stylesheet, not a single instance, so changing a style in one instance of the stylesheet won't be replicated in all the other instances.&lt;/p&gt;

&lt;p&gt;Now this may well not be an issue if you don't need this functionality, in which case crack open the champagne and put your dancing shoes on - you're all set. But if you do, you have a 2 further options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;CSS Custom Properties&lt;/strong&gt; (CSS variables) - CSS custom properties defined on the outer document are available automatically inside your Shadow DOM. So you could define some custom properties in your document, and refer to them in your button's styles. Updating the properties in JavaScript would then apply them to all your button instances. This works but does mean you have to add lots of custom properties if you want to control all aspects of styling, and you still can't add new styles this way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constructable Stylesheets&lt;/strong&gt; - Constructable Stylesheets are a proposal to address the exact issue of reusing the same stylesheet across documents and Shadow roots, and providing a simpler way to add and update styles in a stylesheet. Unfortunately they have only been implemented in Chrome (with only tepid support from other browsers) so they may not be a viable option, although a &lt;a href="https://github.com/calebdwilliams/construct-style-sheets"&gt;polyfill is available&lt;/a&gt;. Find out more in the &lt;a href="https://developers.google.com/web/updates/2019/02/constructable-stylesheets"&gt;Google developer docs&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;Using the same &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag both in your outer document and inside your component's Shadow DOM is currently the best way to share styles across your components without code duplication, while CSS custom properties provide a well supported, albeit somewhat limited, way of dynamically updating shared styles. Constructable Stylesheets promise a better approach to re-using and dynamically updating styles but with limited support at this time.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://eepurl.com/gvjFwv"&gt;Subscribe to my mailing list to be notified of new posts about Web Components and building performant websites&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webcomponents</category>
      <category>html</category>
      <category>css</category>
    </item>
    <item>
      <title>When are the constructor and connectedCallback methods called when creating a Custom Element?</title>
      <dc:creator>Chris Haynes</dc:creator>
      <pubDate>Mon, 15 Mar 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/lamplightdev/when-are-the-constructor-and-connectedcallback-methods-called-when-creating-a-custom-element-lck</link>
      <guid>https://forem.com/lamplightdev/when-are-the-constructor-and-connectedcallback-methods-called-when-creating-a-custom-element-lck</guid>
      <description>&lt;p&gt;The &lt;code&gt;constructor&lt;/code&gt; and &lt;code&gt;connectedCallback&lt;/code&gt; lifecycle methods of Custom Elements are called when your element is created and attached to the DOM respectively, but there are a few subtleties to keep in mind depending on how and when you define, create, insert and declare your element.&lt;/p&gt;

&lt;p&gt;So how are Custom Elements defined, created, inserted and declared? And at which stage do the lifecycle methods get called?&lt;/p&gt;

&lt;h3&gt;
  
  
  Define
&lt;/h3&gt;

&lt;p&gt;A custom element is &lt;strong&gt;defined&lt;/strong&gt; when &lt;code&gt;customElements.define&lt;/code&gt; is called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;constructed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defining an element &lt;strong&gt;doesn't&lt;/strong&gt; trigger either the &lt;code&gt;constructor&lt;/code&gt; or the &lt;code&gt;connectedCallback&lt;/code&gt; methods since it does not create an instance of an element&lt;/p&gt;

&lt;p&gt;An element can only be defined once.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create
&lt;/h3&gt;

&lt;p&gt;An element can be &lt;strong&gt;created&lt;/strong&gt; in JavaScript in two ways:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// can happen before definition&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// can only happen if already defined&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creation triggers the &lt;code&gt;constructor&lt;/code&gt;, &lt;strong&gt;if&lt;/strong&gt; the element has already been defined.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;constructor&lt;/code&gt; is only ever called once per element instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Insert
&lt;/h3&gt;

&lt;p&gt;An element is &lt;strong&gt;inserted&lt;/strong&gt; into the DOM imperatively with JS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Insertion triggers the &lt;code&gt;connectedCallback&lt;/code&gt; method, &lt;strong&gt;if&lt;/strong&gt; the element has already been defined.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;connectedCallback&lt;/code&gt; is called each time the element is inserted into the DOM, with the &lt;code&gt;disconnectedCallback&lt;/code&gt; method called each time it is removed from the DOM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Declare
&lt;/h3&gt;

&lt;p&gt;An element is &lt;strong&gt;declared&lt;/strong&gt; when parsed as HTML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-element&amp;gt;&amp;lt;/my-element&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;my-element&amp;gt;&amp;lt;/my-element&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Declaration triggers the &lt;code&gt;constructor&lt;/code&gt; and &lt;code&gt;connectedCallback&lt;/code&gt; methods, &lt;strong&gt;if&lt;/strong&gt; the element has already been defined.&lt;/p&gt;

&lt;h3&gt;
  
  
  Upgrade
&lt;/h3&gt;

&lt;p&gt;In all the above cases the lifecycle methods are only called if the element has already been defined. An element is &lt;strong&gt;upgraded&lt;/strong&gt; when it already exists before definition - at the point of definition the &lt;code&gt;constructor&lt;/code&gt; is then called automatically. If the element was already attached to the DOM at this point &lt;code&gt;connectedCallback&lt;/code&gt; will also be called.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;The examples below cover the different orders of the above stages to illustrate when the lifecycle methods are called.&lt;/p&gt;

&lt;h3&gt;
  
  
  Define then Declare
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
            &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;constructed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;my-element&amp;gt;&amp;lt;/my-element&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- `constructor` then `connectedCallback` are called here when the element has been parsed --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
   Declare then Define
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;my-element&amp;gt;&amp;lt;/my-element&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
            &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;constructed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// UPGRADE&lt;/span&gt;
            &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="cm"&gt;/**
            `constructor` then `connectedCallback` are called here when the element has been defined --&amp;gt;
            **/&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Define then Create then Insert
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
            &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;constructed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="cm"&gt;/**
            `constructor` called here when element is created
            **/&lt;/span&gt;

            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="cm"&gt;/**
            `connectedCallback` called here when element is inserted
            **/&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
   Create then Insert then Define
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;constructed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// UPGRADE&lt;/span&gt;
            &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="cm"&gt;/**
            `constructor` then `connectedCallback` are called here when the element has been defined --&amp;gt;
            **/&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
   Create then Define then Insert
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;constructed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// UPGRADE&lt;/span&gt;
            &lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="cm"&gt;/**
            `constructor` called here when the element has been defined
            **/&lt;/span&gt;

            &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="cm"&gt;/**
            `connectedCallback` called here when the element has been defined --&amp;gt;
            **/&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why does any of this matter?
&lt;/h2&gt;

&lt;p&gt;Knowing when, how and why the &lt;code&gt;constructor&lt;/code&gt; and &lt;code&gt;connectedCallback&lt;/code&gt; methods are called is important when initialising your Custom Elements. Generally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the &lt;code&gt;constructor&lt;/code&gt; is best suited to setting up initial state and events that don't need to be removed or cleaned up when the element is destroyed (as there is no &lt;code&gt;deconstructor&lt;/code&gt; method.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the &lt;code&gt;constructor&lt;/code&gt; is only ever called once per element so initialisation that needs to happen each time the element is attached to the DOM should be deferred to &lt;code&gt;connectedCallback&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the &lt;code&gt;connectedCallback&lt;/code&gt; method is best suited to most other initialisation tasks. Any clean up can then happen in &lt;code&gt;disconnectedCallback&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;attributes and child elements should not be accessed or modified in the &lt;code&gt;constructor&lt;/code&gt; since, depending on how the element is created, they may not exist e.g. &lt;code&gt;document.createElement('my-element');&lt;/code&gt; - this will trigger the &lt;code&gt;constructor&lt;/code&gt; but the element has had no chance yet to set attributes or children.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if you need to access / modify attributes or children on initialisation this must therefore happen in &lt;code&gt;connectedCallback&lt;/code&gt;. In this case you will often need to guard against such initialisation happening multiple times as the element is removed and re-attached to the DOM.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://eepurl.com/gvjFwv"&gt;Subscribe to my mailing list to be notified of new posts about Web Components and building performant websites&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>vanillajs</category>
    </item>
    <item>
      <title>What's the difference between Web Component attributes and properties?</title>
      <dc:creator>Chris Haynes</dc:creator>
      <pubDate>Thu, 30 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/lamplightdev/what-s-the-difference-between-web-component-attributes-and-properties-36bi</link>
      <guid>https://forem.com/lamplightdev/what-s-the-difference-between-web-component-attributes-and-properties-36bi</guid>
      <description>&lt;p&gt;A common confusion with Web Components is the difference between attributes and properties and the relation between them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attributes
&lt;/h2&gt;

&lt;p&gt;In common with the built in elements, attributes are &lt;strong&gt;strings&lt;/strong&gt; that are set &lt;strong&gt;declaratively&lt;/strong&gt; on the tag itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;my-wc&lt;/span&gt; &lt;span class="na"&gt;myattribute=&lt;/span&gt;&lt;span class="s"&gt;"Ada"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-wc&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;or set &lt;strong&gt;imperatively&lt;/strong&gt; using &lt;code&gt;setAttribute&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myWC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-wc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;myWC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myattribute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ada&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Properties
&lt;/h2&gt;

&lt;p&gt;Properties on the other hand are values of &lt;strong&gt;any type&lt;/strong&gt; that can be set &lt;strong&gt;imperatively&lt;/strong&gt; directly on the element instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myWC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-wc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;myWC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myattribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lovelace&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// the value could be any type - string, number, boolean, object, function etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Relationship between attributes and properties
&lt;/h2&gt;

&lt;p&gt;By default there is none - they can co-exist with the same name and changing one has no effect on the other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myWC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myattribute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 'Ada'&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myWC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myattribute&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 'Lovelace'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Of course that can be confusing in contrast with most of the built in elements where there is a relationship between attributes and properties with the same name. There are generally two scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The declared attribute initialises a property with the same name, but subsequent changes to the attribute have no effect on the property, and likewise changes to the property are not reflected in an updated attribute value. This is how the &lt;code&gt;value&lt;/code&gt; attribute/property pairing works on the standard &lt;code&gt;input&lt;/code&gt; element.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The attribute and property are always kept in sync - any changes to the property are reflected in the attribute and vice-versa. An example of this is the &lt;code&gt;id&lt;/code&gt; attribute/property pairing of all elements.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So how do we reproduce these two scenarios on our new element which has no attribute/property relationship by default? To do this we need to manually set up the relationship ourselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the attribute as a property initialiser
&lt;/h2&gt;

&lt;p&gt;This is the simplest case - all we need to do is check the value of the attribute when the element is added to the DOM - the property will then take the value of the attribute currently defined (either in the markup, or set using &lt;code&gt;setAttribute&lt;/code&gt; on a programmatically defined instance):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyWC&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myattribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Kevin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// our default property value&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;attributeValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myattribute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Note non-existant attributes will return null&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attributeValue&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myattribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attributeValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Keeping the attribute and property in sync
&lt;/h2&gt;

&lt;p&gt;This scenario takes more set up - we need to monitor the attribute and property for changes so we can mirror the values to each other:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyWC&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ensure `attributeChangedCallback` is called when our attribute changes:&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;observedAttributes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myattribute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// We need to store our property value in a new object - without this&lt;/span&gt;
    &lt;span class="c1"&gt;// we can't use the getter/setters we need below&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;myattribute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Kevin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;attributeValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myattribute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Note non-existant attributes will return null&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attributeValue&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myattribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attributeValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;myattribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// return our property value&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myattribute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;myattribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// set our property value&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myattribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// update our attribute of the same name&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myattribute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;attributeChangedCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myattribute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// when our attribute changes update our property value&lt;/span&gt;
      &lt;span class="c1"&gt;// we can't set the property using the setter (i.e. this.myattribute = value)&lt;/span&gt;
      &lt;span class="c1"&gt;// as this would cause an infinite loop&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myattribute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Keep in mind the above implementations are for string based properties - you'll need a few extra steps for boolean or numeric properties. Non-primitive types (functions, objects, etc.) are not generally reflected to or initialised from attributes.&lt;/p&gt;

&lt;p&gt;There is also a convention to camelCase (e.g. &lt;code&gt;myAttribute&lt;/code&gt;) property names and kebab-case attribute names (e.g. &lt;code&gt;my-attribute&lt;/code&gt;). This conversion would also require some further steps not detailed above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which scenario should I choose?
&lt;/h2&gt;

&lt;p&gt;Initialising properties from attributes is the simplest choice, and the one I would recommend unless you have a reason not to. However there are times when it's useful to keep the attribute value in sync with the property value - a common case is being able to use CSS attribute selectors to match elements depending on their current state - in which case the second method is required.&lt;/p&gt;

</description>
      <category>webcomponents</category>
    </item>
    <item>
      <title>Showing different fallback content with Web Components</title>
      <dc:creator>Chris Haynes</dc:creator>
      <pubDate>Thu, 23 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/lamplightdev/showing-different-fallback-content-with-web-components-l2e</link>
      <guid>https://forem.com/lamplightdev/showing-different-fallback-content-with-web-components-l2e</guid>
      <description>&lt;p&gt;With web components there's often a need to render fallback content - both to show content in browsers that &lt;strong&gt;don't have support for web components&lt;/strong&gt; (or with JavaScript disabled/broken) and to show content to the user &lt;strong&gt;while the web component is being loaded/initialised&lt;/strong&gt;. The trouble is that we probably want to display &lt;strong&gt;different fallback content&lt;/strong&gt; in these two scenarios - perhaps alternative static content in the first case and a loading indicator in the latter.&lt;/p&gt;

&lt;p&gt;Fallback content is provided by supplying HTML between our custom element tags, but how do we have 2 different version of fallback content?&lt;/p&gt;

&lt;p&gt;To achieve this we first build our component as normal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;WCExample&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
      &amp;lt;style&amp;gt;
      :host {
        display: block;
        padding: 1rem;
        color: steelblue;
        border: 1px solid steelblue;
      }
      &amp;lt;/style&amp;gt;

      &amp;lt;p&amp;gt;Loaded and ready to go!&amp;lt;/p&amp;gt;
    `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wc-example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WCExample&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next we provide our two versions of fallback content inside out new element, providing different classes to each:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;wc-example&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"no-wc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    A static version of the content
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"has-wc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Please wait...
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/wc-example&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If we were to load this HTML in the browser we'd see both versions of the fallback content until the component code is loaded. However if we apply a class to the &lt;code&gt;body&lt;/code&gt; indicating no web component support, &lt;code&gt;.no-wc&lt;/code&gt;, and immediately remove it just after the &lt;code&gt;body&lt;/code&gt; tag if web components are supported (before the component code is loaded or the component tag is rendered):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-wc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The body will then only have the &lt;code&gt;.no-wc&lt;/code&gt; class if JavaScript has run and Web Components are supported. We can then control which version is displayed with a couple of global CSS rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nc"&gt;.no-wc&lt;/span&gt; &lt;span class="nc"&gt;.has-wc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="nd"&gt;:not&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;.no-wc&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;.no-wc&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://fallback-content-with-web-components.glitch.me/"&gt;See this in action here&lt;/a&gt; (with an artifical delay applied to the loading of the Web Component code). Be sure to test with and without JavaScipt enabled to see the difference.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>progressiveenhancement</category>
    </item>
    <item>
      <title>Lazy loading Web Components with Intersection Observer</title>
      <dc:creator>Chris Haynes</dc:creator>
      <pubDate>Fri, 20 Mar 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/lamplightdev/lazy-loading-web-components-with-intersection-observer-30m2</link>
      <guid>https://forem.com/lamplightdev/lazy-loading-web-components-with-intersection-observer-30m2</guid>
      <description>&lt;p&gt;One of the many benefits of adopting Web Components (WC) as your component model of choice is that you can make direct use native web platform features with no modifications, wrappers or build scripts. One such example is using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API"&gt;Intersection Observer API&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports"&gt;dynamic imports&lt;/a&gt; to load WC only when they're needed on the page. Using this pattern defers the loading of the component source on modern browsers until the tag is visible on the page, so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if a user visits on a browser that can't or won't run JavaScript, they won't download the JS that they'll never use&lt;/li&gt;
&lt;li&gt;if a user visits on a browser that doesn't support WC, they won't download the JS that they'll never use.&lt;/li&gt;
&lt;li&gt;if a user visits on a browser that does support WC but doesn't visit a page containing the WC, they won't download the JS that they'll never use&lt;/li&gt;
&lt;li&gt;if a user visits on a browser that does support WC and does visit a page containing the WC, but doesn't scroll to the part of the page that contains the WC, they won't download the JS that they'll never use&lt;/li&gt;
&lt;li&gt;if a user visits on a browser that does support WC and does visit a page containing the WC, and does scroll to the part of the page that contains the WC, they'll download the JS that they require on demand.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this way we can progressively enhance the user experience not only based on browser features, but also only when a component is actually required. All this can be achieved with just a few lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// keep a record of the components we've loaded in this way&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imported&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
&lt;span class="c1"&gt;// Set up our observer:&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;observerRef&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// The callback is run when the visibility of one or more of the elements&lt;/span&gt;
  &lt;span class="c1"&gt;// being observed has changed. It's also called on page load.&lt;/span&gt;
  &lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//`isIntersecting` will be `true` if any part of the element is currently visible&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// We are assuming here that your Web Component is located in a file&lt;/span&gt;
      &lt;span class="c1"&gt;// named after it's tag name&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodeName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="c1"&gt;// Once we've observed this element come into view, we can safely remove&lt;/span&gt;
      &lt;span class="c1"&gt;// the observer since we won't need to import the WC code again&lt;/span&gt;
      &lt;span class="nx"&gt;observerRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unobserve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;imported&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Keep a note of which WCs have been loaded so if we have multiple&lt;/span&gt;
        &lt;span class="c1"&gt;// instances we don't import twice&lt;/span&gt;
        &lt;span class="nx"&gt;imported&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Let's load the WC code&lt;/span&gt;
        &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`./&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.js`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Observe all components with the desired class&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;els&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.dynamic-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;els&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And that's it. The observer callback is run when the visibility of one or more of the elements being observed has changed. There are 3 scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The element has just come into view&lt;/li&gt;
&lt;li&gt;The amount of the element that's visible has changed&lt;/li&gt;
&lt;li&gt;The element has just gone out of view&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here we're only interested in the first case so &lt;code&gt;isIntersecting&lt;/code&gt; is all we need - when that's &lt;code&gt;true&lt;/code&gt; we know the component has just come into view and we can import the required code. We can also detach the observer so it's not called again when the element (or others of the same type) come into view again. Note that the observer is always run on page load so that if there's a component on screen when the page is loaded it's immediately imported.&lt;/p&gt;

&lt;p&gt;I've added an example on &lt;a href="https://lamplightdev.com/blog/2020/03/20/lazy-loading-web-components-with-intersection-observer/"&gt;my site's version of this post&lt;/a&gt;. By the time you've scrolled to the end of the page the browser will have dynamically loaded the &lt;code&gt;&amp;lt;lamplight-lazy&amp;gt;&amp;lt;/lamplight-lazy&amp;gt;&lt;/code&gt; component (check in devtools to see the &lt;code&gt;lamplight-lazy.js&lt;/code&gt; file loaded when you scroll to this point.)&lt;/p&gt;

&lt;p&gt;Thanks for reading, and let me know if you have any other tips for progressive enhancement with Web Components!&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>progressiveenhancement</category>
    </item>
    <item>
      <title>Web Components aren't a framework replacement - they're better than that</title>
      <dc:creator>Chris Haynes</dc:creator>
      <pubDate>Sat, 18 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://forem.com/lamplightdev/web-components-aren-t-a-framework-replacement-they-re-better-than-that-1ck0</link>
      <guid>https://forem.com/lamplightdev/web-components-aren-t-a-framework-replacement-they-re-better-than-that-1ck0</guid>
      <description>&lt;p&gt;With the release of the Chromium based Edge browser, and Web Components now being available in all major browsers, it's worth taking a moment to discuss what Web Components are, what they are not, and how they relate to the established UI frameworks such as React, Vue, and Angular.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identity problem
&lt;/h2&gt;

&lt;p&gt;Web Components mean different things to different people. Officially they a group of 3 language features:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements"&gt;Custom Elements&lt;/a&gt; - a set of APIs to create new HTML elements&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM"&gt;Shadow DOM&lt;/a&gt; - the ability to encapsulate both the DOM and styling inside an element&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots"&gt;HTML Templates&lt;/a&gt; - a way of creating DOM independent of the current document&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While this grouping makes sense in that all three can be used while creating Web Components, only Custom Elements themselves are required to create one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shadow DOM&lt;/strong&gt; is a great addition to the web, but you can create Web Components without it (indeed you can even use Shadow DOM outside of Custom Elements, although I'm not sure why you'd want to).&lt;/p&gt;

&lt;p&gt;Similarly &lt;strong&gt;HTML Templates&lt;/strong&gt; can be used with Web Components but are by no means necessary, and have a wider use outside of Web Components. For these reasons I prefer to think of Web Components as Custom Elements only, and refer to the Shadow DOM and/or HTML Templates explicitly when used.&lt;/p&gt;

&lt;p&gt;For the remainder of this post the term Web Components (WC) will refer to Custom Elements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building blocks
&lt;/h2&gt;

&lt;p&gt;Let's consider what Web Components are trying to achieve. As part of the extensible web their aim is to provide a &lt;strong&gt;basic building block for the web&lt;/strong&gt; on top of which extra functionality can be added by developers as and when needed. The most fundamental building block of any web site or application are the HTML elements themselves. Built in elements encapsulate their functionality and styling independent of other elements on the page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built-in HTML elements
&lt;/h3&gt;

&lt;p&gt;Think of the &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element - you provide it a source video and it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;knows how to play that video&lt;/li&gt;
&lt;li&gt;exposes methods for the developer to control the video&lt;/li&gt;
&lt;li&gt;styles it's controls independently of any outside styling&lt;/li&gt;
&lt;li&gt;can be manipulated with the standard Javascript DOM API&lt;/li&gt;
&lt;li&gt;manages its own lifecycle events such as when it's added or removed from the DOM&lt;/li&gt;
&lt;li&gt;integrates seamlessly with DOM based frameworks such as Vue, Angular and many others.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WC provide developers with the ability to create their own HTML elements that behave in exactly the same way as native elements, and can be manipulated with the same native DOM APIs in the browser. As such you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use a WC in a site developed 10 years ago with jQuery.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Re-use a WC internally in a variety of frameworks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use a WC developed today in 5 years time with the latest framework.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use a WC in a simple HTML page with no framework or library.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's in the box
&lt;/h2&gt;

&lt;p&gt;In common with the frameworks, WC provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Component model&lt;/strong&gt; - a way of encapsulating the functional behaviour of the component&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component lifecycle&lt;/strong&gt; - methods that can be used to control the behaviour of the component when it's added, removed and updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition WC uniquely provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Style and content encapsulation&lt;/strong&gt; - through the (optional) use of Shadow DOM the internals of the WC can be styled independently of the containing document. CSS rules are scoped to the element so the element will not inherit unwanted styling from the outside, and &lt;code&gt;id&lt;/code&gt;s and &lt;code&gt;classes&lt;/code&gt; and any other attributes are scoped to the component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interoperability&lt;/strong&gt; - because they are true HTML elements they they can be used anywhere HTML is expected and are entirely interoperable with past, current and future libraries that deal with HTML elements directly. See &lt;a href="https://custom-elements-everywhere.com/"&gt;Custom Elements Everywhere&lt;/a&gt; for full list of interoperable frameworks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native implementation&lt;/strong&gt; - WC are provided built-in to the browser, so there are no 3rd party sources to load, parse, update, or maintain, and no build steps to incorporate. This makes them performant by default.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The missing parts
&lt;/h2&gt;

&lt;p&gt;What WC don't provide, but frameworks do, is any model for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Managing component state&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reactivity&lt;/strong&gt; - updating of the component when that state changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Declarative templating&lt;/strong&gt; for non-string properties&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server side rendering (SSR)&lt;/strong&gt; - enabling the component to be fully rendered on the server as sent as a string to the browser so that it can be displayed (although not fully functional) without JavaScript.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first two of these features are seen as key to writing modern day web apps, and rightly so - handling state and updating elements manually can quickly become cumbersome as the complexity of the app increases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Declarative templating&lt;/strong&gt; is a harder comparison to make - while string properties (or more correctly attributes) can be set declaratively, e.g.:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;x-component description="Product"&amp;gt;&amp;lt;/x-component&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;non-string properties (Number, Object, Function etc.) must be set in JavaScript. This is due to the nature of HTML itself - being a markup language there is no way to define non-string properties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server side rendering&lt;/strong&gt; is also more complicated. &lt;a href="https://lamplightdev.com/blog/2019/07/20/how-to-server-side-render-web-components/"&gt;WC can be rendered on the server&lt;/a&gt; since they are just written as HTML elements, but WC making use of the Shadow DOM cannot be without making use of a server side DOM implementation. Even then workarounds must be found to apply styling since the Shadow DOM style is only applied once the component has been instantiated in JavaScript. &lt;a href="https://github.com/whatwg/dom/issues/510"&gt;A declarative Shadow DOM&lt;/a&gt; would solve this issue, but that seems some way off at this point, if at all. However with search engines now able to crawl Shadow DOM, and a potential performance cost (sending the component twice, once as an SSR string and again in the component definition) the necessity of SSR may be less important.&lt;/p&gt;

&lt;p&gt;The conclusion often made from this is that WC are only suited to being leaf nodes - small self contained elements that are included inside larger more complex apps - and are not suited to being used for building the apps themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  A third way
&lt;/h2&gt;

&lt;p&gt;So WC alone are not a replacement for a framework - but they were never intended to be. By their very nature they provide a native, interoperable base on top of which developers can add further functionality if required. In the simplest cases they can be used as-is to build small, performant, re-usable components, but there's nothing to stop component authors adding state management, reactiveness, declaritive templating and more when the need arises. Indeed there are already several well established libraries that enable this functionality to be applied to WC such as &lt;a href="https://lit-html.polymer-project.org/"&gt;lit-html&lt;/a&gt; and &lt;a href="https://lit-element.polymer-project.org/"&gt;lit-element&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Indeed having the flexibility to choose when and how these features are integrated in to your component can be seen as an advantage too. They become an implementation detail that can be changed as and when necessary, and because their interface remains the standard HTML element no change is needed in the way they are used whatever the internal details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;


&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Web Components&lt;/th&gt;
&lt;th&gt;Frameworks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Component model&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Component lifecycle&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Style encapsulation&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✗&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native implementation&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✗&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interoperability&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✗&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server side rendering&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓ (without Shadow DOM)&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Declarative templating&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✗&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State management&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✗&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reactive updates&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✗&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&lt;span&gt;✓&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;p&gt;So it's clear that when deciding to use Web Components, it's not a direct choice between them and a framework.&lt;/p&gt;

&lt;p&gt;Existing frameworks provide an all in one solution to building web UIs, but they do so at the expense of locking component authors into their particular implementations and eco-systems. This results in components that are not interoperable or re-usable outside of the chosen framework.&lt;/p&gt;

&lt;p&gt;On the other hand native Web Components are fully interoperable and re-usable both inside and outside of existing frameworks and anywhere HTML is used, whilst not providing everything that might be needed to write a complex web app. These 'missing parts' however can be provided quite easily with existing libraries as and when needed, and as Web Components become more popular the range of options to add this functionality will only increase.&lt;/p&gt;

</description>
      <category>webcomponents</category>
    </item>
    <item>
      <title>How to server side render Web Components</title>
      <dc:creator>Chris Haynes</dc:creator>
      <pubDate>Sat, 20 Jul 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/lamplightdev/how-to-server-side-render-web-components-4ad7</link>
      <guid>https://forem.com/lamplightdev/how-to-server-side-render-web-components-4ad7</guid>
      <description>&lt;p&gt;Almost all modern framworks provide a way to &lt;strong&gt;server side render&lt;/strong&gt; (SSR) a web site by running the framework code on a JavaScipt server side framework, such as express, to produce an &lt;strong&gt;intial string of HTML&lt;/strong&gt; that can be sent to the browser. The same component code that runs in the browser is also run on the server.&lt;/p&gt;

&lt;p&gt;With Web Components there are several limitations when it comes to SSR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it’s not possible to run the same code on the server since &lt;strong&gt;Web Components rely on browser specific DOM APIs&lt;/strong&gt; that are not available unless you fire up a headless browser or an alternative DOM implementation. Both of these solutions bring a non-trivial overhead that is hard to justify.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadow DOM cannot (&lt;a href="https://github.com/whatwg/dom/issues/510"&gt;currently&lt;/a&gt;) be represented declaratively&lt;/strong&gt; so you cannot send it over in your initial string of HTML. Instead you’ll need to implement some other style encapsulation solution (much like the frameworks do.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So Web Components are certainly at a disadvantage here compared to framework components, but they still offer &lt;strong&gt;two main advantages&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;less code that runs faster as they use &lt;strong&gt;built in platform APIs&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;future proof as they can be &lt;strong&gt;used anywhere&lt;/strong&gt; , including within current and future frameworks, without modification or risk of obsolesence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if these advantages are enough for you to choose Web Components over framework components, &lt;strong&gt;how can you SSR Web Components?&lt;/strong&gt; Well since &lt;strong&gt;Web Components without the Shadow DOM are just standard HTML&lt;/strong&gt; , it’s straightforward.&lt;/p&gt;

&lt;p&gt;We’ll use a simple Twitter share button as an example. To see the final result have a look at the &lt;a href="https://grave-mirror.glitch.me/"&gt;demo&lt;/a&gt; (or &lt;a href="https://glitch.com/edit/#!/grave-mirror?path=public/twitter-share.html:1:0"&gt;browse the code&lt;/a&gt;) and try with and without JavaScript enabled.&lt;/p&gt;

&lt;h3&gt;
  
  
  On the client
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This is a simplified implementation that uses the initial attributes to render the component, with no reactivity to updated attributes or properties - but there is no reason why this could not be added at a later stage in the browser specific part of the code, using vanilla JavaScript or a 3rd party library (for example &lt;a href="https://lit-html.polymer-project.org/"&gt;lit-html&lt;/a&gt; and/or &lt;a href="https://lit-element.polymer-project.org/"&gt;lit-element&lt;/a&gt;). If you do go down this route also checkout &lt;a href="https://github.com/popeindustries/lit-html-server"&gt;lit-html-server&lt;/a&gt; which let’s you use the lit-html syntax on the server.&lt;/p&gt;

&lt;p&gt;Our &lt;strong&gt;initial, browser based, web component&lt;/strong&gt; may look something like this:&lt;/p&gt;

&lt;h4&gt;
  
  
  twitter-share.js
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;TwitterShare&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// set up the props based on the inital attribute values&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodeName&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nodeValue&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// set the innerHTML manually - ShadowDOM can't be used&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// add an event listener to the link inside the component&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// create the HTML needed for the component&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hashtags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;via&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;related&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`text=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`url=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;hashtags&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`hashtags=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hashtags&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;via&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`via=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;via&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;related&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`related=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;related&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://twitter.com/intent/tweet?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`
      &amp;lt;a target="_blank" noreferrer href="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;
        Tweet this
      &amp;lt;/a&amp;gt;
    `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// open the twitter share url in a popup window when the link is clicked&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;features&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`width=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,height=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,left=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,top=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;href&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_blank&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;features&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;twitter-share&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TwitterShare&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, to render this on the server you can’t use &lt;code&gt;HTMLElement&lt;/code&gt;, &lt;code&gt;customElements&lt;/code&gt; or &lt;code&gt;addEventListener&lt;/code&gt; for example as those &lt;strong&gt;APIs don’t exist on the server&lt;/strong&gt; , so you’ll need to &lt;strong&gt;extract the template method into a standalone function&lt;/strong&gt; that can be used:&lt;/p&gt;

&lt;h4&gt;
  
  
  twitter-share-template.mjs
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// .mjs is used here so javascript modules can be used on the server&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// the same logic as above, in a self contained function&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hashtags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;via&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;related&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`text=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`url=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;hashtags&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`hashtags=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;hashtags&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;via&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`via=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;via&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;related&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s2"&gt;`related=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;related&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;amp;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://twitter.com/intent/tweet?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;a target="_blank" noreferrer href="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;
      Tweet this
    &amp;lt;/a&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and &lt;strong&gt;update our browser based component definition&lt;/strong&gt; to import and use that function:&lt;/p&gt;

&lt;h4&gt;
  
  
  twitter-share.js
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./twitter-share-template.mjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;TwitterShare&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;//...as before&lt;/span&gt;

  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ...as before&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// template() -&amp;gt; removed&lt;/span&gt;

  &lt;span class="c1"&gt;// ...as before&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;twitter-share&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TwitterShare&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  On the server
&lt;/h3&gt;

&lt;p&gt;On the server, while constructing the page response you need to use the &lt;strong&gt;HTML tag for our component with the necessary attributes&lt;/strong&gt; that will be parsed by the browser, and for the &lt;strong&gt;SSR content of the component use the same &lt;code&gt;template&lt;/code&gt; function&lt;/strong&gt; as above:&lt;/p&gt;

&lt;h4&gt;
  
  
  server.mjs
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;template&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./public/js/twitter-share-template.mjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ... the server side route&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A Twitter share button with progressive enhancement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://grave-mirror.glitch.me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;via&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lamplightdev&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// be sure to sanatize the props if including directly in HTML&lt;/span&gt;

&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
  &amp;lt;twitter-share text="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" url="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" via="&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;via&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;
    &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
  &amp;lt;/twitter-share&amp;gt;
`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To see the component in action have a look at the &lt;a href="https://grave-mirror.glitch.me/"&gt;demo&lt;/a&gt; and &lt;a href="https://glitch.com/edit/#!/grave-mirror?path=public/twitter-share.html:1:0"&gt;browse the code&lt;/a&gt;. Be sure to try the page with and without JavaScript enabled.&lt;/p&gt;

&lt;p&gt;In summary, &lt;strong&gt;you can SSR web components without any server side DOM implementation, but only without the Shadow DOM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you have any feedback or questions I’d love to hear them &lt;a href="https://twitter.com/lamlightdev.com"&gt;@lamplightdev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://eepurl.com/gvjFwv"&gt;Subscribe to the mailing list to be notified of new posts about Web Components and building performant websites&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ssr</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>Why is my Web Component inheriting styles?</title>
      <dc:creator>Chris Haynes</dc:creator>
      <pubDate>Tue, 26 Mar 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/lamplightdev/why-is-my-web-component-inheriting-styles-of3</link>
      <guid>https://forem.com/lamplightdev/why-is-my-web-component-inheriting-styles-of3</guid>
      <description>&lt;p&gt;One of the great features of the Shadow DOM in Web Components is that styles are encapsulated to the component - you can style your component without worrying about any specifier (&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;class&lt;/code&gt;, etc.) conflicts or styles ‘leaking out’ to other elements on the page.&lt;/p&gt;

&lt;p&gt;This often leads to the belief that the reverse is true - that styles outside of the component won’t cross the Shadow boundary and ‘leak in’ to your component. However this is only partly true.&lt;/p&gt;

&lt;p&gt;While &lt;em&gt;specifiers&lt;/em&gt; do not leak in to your component (e.g. a color applied to an &lt;code&gt;p&lt;/code&gt; element in a style rule outside of your component won’t effect any &lt;code&gt;p&lt;/code&gt; elements in your Shadow DOM, although the rule will be applied to your Light DOM, or slotted content), &lt;em&gt;inheritable styles&lt;/em&gt; applied to any elements containing your component will be applied to both your Shadow and Light DOM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inheritable styles
&lt;/h3&gt;

&lt;p&gt;Inheritable styles are those that are defined on a parent that are then inherited by child elements. The most obvious inheritable styles are those defined on the &lt;code&gt;html&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt; tags. Taking &lt;code&gt;color&lt;/code&gt; as an example, if there is a &lt;code&gt;color: green&lt;/code&gt; set on the &lt;code&gt;body&lt;/code&gt; (which is a container for every element on the page), this will be inherited by all elements on the page, including Web Components, unless overriden by another more specific rule.&lt;/p&gt;

&lt;p&gt;Inheritable styles are necessary so we don’t, for example, have to write a &lt;code&gt;color&lt;/code&gt; rule on every element. But not all styles are inheritable, otherwise a &lt;code&gt;border&lt;/code&gt; style on one element would be inherited by all its children:&lt;/p&gt;


&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/uttermost-leaf?path=index.html" alt="uttermost-leaf on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;p&gt;Rules set in the Shadow DOM act in the same way - inheritable styles are applied to all children (Shadow and Light DOM), so adding a &lt;code&gt;color: red&lt;/code&gt; to our Shadow DOM:&lt;/p&gt;


&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/sprout-caraway?path=index.html" alt="sprout-caraway on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  The chosen ones
&lt;/h3&gt;

&lt;p&gt;So which styles are inheritable, and which are not? Well these are all defined by the &lt;a href="https://www.w3.org/TR/CSS22/propidx.html#q0"&gt;CSS spec&lt;/a&gt;. The most common ones are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;color&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cursor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;direction&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;font-*&lt;/code&gt; (&lt;code&gt;font-family&lt;/code&gt;, &lt;code&gt;font-size&lt;/code&gt; etc.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;letter-spacing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;line-height&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text-align&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text-indent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text-transform&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;visibility&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;word-spacing&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So that’s why these styles &lt;em&gt;do&lt;/em&gt; leak into your Web Component.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if I don’t want my component to inherit from its parent?
&lt;/h3&gt;

&lt;p&gt;Well you’re in luck, you can reset all inheritable styles for a component (Shadow and Light DOM) using &lt;code&gt;all: initial&lt;/code&gt;, which resets the styles back to the CSS defaults or those defined in the browser ‘user agent stylesheet’. Note that outside specifiers matching in the Light DOM will not be reset.&lt;/p&gt;


&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/sticky-tartan?path=index.html" alt="sticky-tartan on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  What if I want to style my component from outside?
&lt;/h3&gt;

&lt;p&gt;Well that’s where CSS custom properties come in, along with the new &lt;code&gt;::part&lt;/code&gt; and &lt;code&gt;::theme&lt;/code&gt; pseudo-elements, and I’ll cover that in an upcoming post.&lt;/p&gt;

&lt;p&gt;If you have any feedback or questions I’d love to hear them &lt;a href="https://twitter.com/lamlightdev.com"&gt;@lamplightdev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://eepurl.com/gvjFwv"&gt;Subscribe to the mailing list to be notified of new posts about Web Components and building performant websites&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webcomponents</category>
    </item>
    <item>
      <title>How to pass data between Web Components?</title>
      <dc:creator>Chris Haynes</dc:creator>
      <pubDate>Wed, 13 Mar 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/lamplightdev/how-to-pass-data-between-web-components-21c8</link>
      <guid>https://forem.com/lamplightdev/how-to-pass-data-between-web-components-21c8</guid>
      <description>&lt;p&gt;A common question to those first experimenting with Web Components is how to communicate between different components on the same page. It might seem at first sight that the very thing Web Components are designed for - encapsulating DOM, CSS and behaviour inside of discrete elements - means that they are not suited to communicating outside their boundary with their fellow elements. But passing data is just a matter of using the standard JavaScript event model you’re already familiar with.&lt;/p&gt;

&lt;p&gt;Part of the confusion may be due to the fact this topic is often left out of introductions to Web Components. Articles understandably concentrate on all the new functionality that Web Components provide, but the other great advantage they have is that they’re just an extension to the existing native web platform - all the techniques and APIs (old and new) of the web are available to you when building components.&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript Event Model in Web Components
&lt;/h3&gt;

&lt;p&gt;The native event model of the web consists simply of the dispatch and listening to of events using &lt;code&gt;dispatchEvent&lt;/code&gt; and &lt;code&gt;addEventListener&lt;/code&gt;, and the same methodology is used with Web Components.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;CustomEvent&lt;/code&gt; is a user defined event with a given name that can be sent from the component to the containing DOM using &lt;code&gt;dispatchEvent&lt;/code&gt;:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;bubbles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// bubble event to containing elements&lt;/span&gt;
    &lt;span class="na"&gt;composed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// let the event pass through the shadowDOM boundary&lt;/span&gt;
    &lt;span class="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// an object to hold any custom data that's attached to this event&lt;/span&gt;
      &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Note the &lt;code&gt;composed&lt;/code&gt; property which needs to be set to enable the event to ‘escape’ the encapsulation of the ShadowDOM. Without this, the event would still be propagated up inside the shadowDOM, but no further.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;x-increment&lt;/code&gt; event can then be captured by any containing element using &lt;code&gt;addEventListener&lt;/code&gt;, and any data extracted and used directly, or passed down to a child component:&lt;/p&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// attach shadowDOM here&lt;/span&gt;

  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-increment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// extract data&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;

    &lt;span class="c1"&gt;// pass down to a child&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shadowRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-target&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Managing state with a container component
&lt;/h3&gt;

&lt;p&gt;A useful pattern to follow is to have a containing component that manages the application state by capturing child events and passing data back down the hierarchy. In this way state is always passed down the component tree in a uni-directional manner (a.k.a. one-way data binding) in a way that may be familiar from other UI frameworks.&lt;/p&gt;

&lt;p&gt;Here’s a basic example that shows the above techniques in action to provide a simple counter. It consists of a &lt;code&gt;x-controls&lt;/code&gt; component to hold the inputs, a &lt;code&gt;x-counter&lt;/code&gt; component to show the output, and a &lt;code&gt;x-container&lt;/code&gt; component to manage the application state and pass it down as properties to the other components.&lt;/p&gt;


&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/morning-yam?path=index.html" alt="morning-yam on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;



&lt;p&gt;In upcoming posts we’ll have a closer look at ways the above application can be improved by generalising the handling of properties, using a templating library to declaratively update the DOM and attach event handlers, managing styles in web components, and much more.&lt;/p&gt;

&lt;p&gt;If you have any feedback or questions I’d love to hear them &lt;a href="https://twitter.com/lamlightdev.com"&gt;@lamplightdev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://eepurl.com/gvjFwv"&gt;Subscribe to the mailing list to be notified of new posts about Web Components and building performant websites&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webcomponents</category>
    </item>
  </channel>
</rss>
