<?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: CoderPad Team</title>
    <description>The latest articles on Forem by CoderPad Team (@coderpad_team).</description>
    <link>https://forem.com/coderpad_team</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%2F633043%2F64ca48e6-53d2-4ebe-9c10-c9dc495da873.jpg</url>
      <title>Forem: CoderPad Team</title>
      <link>https://forem.com/coderpad_team</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/coderpad_team"/>
    <language>en</language>
    <item>
      <title>Web Components 101: History</title>
      <dc:creator>CoderPad Team</dc:creator>
      <pubDate>Thu, 07 Apr 2022 23:06:19 +0000</pubDate>
      <link>https://forem.com/coderpad/web-components-101-history-2p24</link>
      <guid>https://forem.com/coderpad/web-components-101-history-2p24</guid>
      <description>&lt;p&gt;Web components enjoy large-scale usage today. From YouTube to GitHub and many other major organizations, it’s safe to say they’ve made their way into commonplace frontend development practices. &lt;/p&gt;

&lt;p&gt;That wasn’t always the case. After all, web components had to start somewhere. And web development can be particularly picky with what succeeds and what doesn’t.&lt;/p&gt;

&lt;p&gt;So then, how did web components succeed? What was their path to broad adoption? And what are the origins behind the APIs used for modern web components?&lt;/p&gt;

&lt;p&gt;Let’s walk through a short history of web components and the related ecosystem to answer these questions.&lt;/p&gt;

&lt;h1&gt;
  
  
  2010: The Early Days of MVC in JS
&lt;/h1&gt;

&lt;p&gt;While the concept of &lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" rel="noopener noreferrer"&gt;“Model View Controller”, also commonly called MVC&lt;/a&gt;, has been around for some time, in JavaScript itself it failed to take hold early on.&lt;/p&gt;

&lt;p&gt;However, in 2010, there was an explosion around MVC and it’s related cousin: Model View View-Controller (MVVC) ). This explosion came courtesy of a slew of new frameworks that launched only a few months apart from one-another.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/knockout/knockout/releases/tag/v1.0.0" rel="noopener noreferrer"&gt;Knockout was one of the first to introduce strict MVC patterns inside of JavaScript in July 2010&lt;/a&gt;. Knockout supported observable-based UI binding. Here, you could declare a Model, and bind data from said model directly to your 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="c"&gt;&amp;lt;!-- Demo of KnockoutJS --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mails"&lt;/span&gt; &lt;span class="na"&gt;data-bind=&lt;/span&gt;&lt;span class="s"&gt;"with: chosenFolderData"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&lt;/span&gt;Subject&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tbody&lt;/span&gt; &lt;span class="na"&gt;data-bind=&lt;/span&gt;&lt;span class="s"&gt;"foreach: mails"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;data-bind=&lt;/span&gt;&lt;span class="s"&gt;"text: subject"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tbody&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;WebmailViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Data&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nb"&gt;self&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="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chosenFolderData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/mail&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;folder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Inbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chosenFolderData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;ko&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;applyBindings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebmailViewModel&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F12%2Fimg_61c249d556901.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F12%2Fimg_61c249d556901.png" alt="img"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this works great for UI binding, it lacks the componentization aspect we’ve come to expect from modern frameworks.&lt;/p&gt;




&lt;p&gt;This was improved in the ecosystem when &lt;a href="https://github.com/jashkenas/backbone/releases/tag/0.1.0" rel="noopener noreferrer"&gt;Backbone saw its first release in October 2010&lt;/a&gt;. It introduced a &lt;a href="https://backbonejs.org/#View-extend" rel="noopener noreferrer"&gt;&lt;code&gt;View&lt;/code&gt;&lt;/a&gt;, similar to what we might expect a component to be like today.&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;var&lt;/span&gt; &lt;span class="nx"&gt;DocumentRow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Backbone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;View&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tagName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;li&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;document-row&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click .icon&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="s2"&gt;open&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="s2"&gt;click .button.edit&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="s2"&gt;openEditDialog&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="s2"&gt;click .button.delete&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="s2"&gt;destroy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&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="nf"&gt;listenTo&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;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&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;render&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we can see that we can now bind events, classes, and more to a single tag. This aligns better with the types of components we’d see in, say, React or Lit.&lt;/p&gt;




&lt;p&gt;But that’s not all we saw in October that year. We also saw the &lt;a href="https://github.com/angular/angular.js/releases/tag/v0.9.0" rel="noopener noreferrer"&gt;initial release of Angular.js&lt;/a&gt; only 10 days after Backbone’s release.&lt;/p&gt;

&lt;p&gt;Here, we can see that it introduced a concept of controllers into the document, similar to the &lt;code&gt;Model&lt;/code&gt;s of Knockout. It allowed two-way bindings from UI to data and back.&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;div&lt;/span&gt; &lt;span class="na"&gt;ng-controller=&lt;/span&gt;&lt;span class="s"&gt;"TodoListController as todoList"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;ng-repeat=&lt;/span&gt;&lt;span class="s"&gt;"todo in todoList.todos"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{todo.text}}&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;ng-submit=&lt;/span&gt;&lt;span class="s"&gt;"todoList.addTodo()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
      &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
      &lt;span class="na"&gt;ng-model=&lt;/span&gt;&lt;span class="s"&gt;"todoList.todoText"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn-primary"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"add"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;angular&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;module&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;todoApp&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="nf"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TodoListController&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;todoList&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;todoList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&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;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;learn AngularJS&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;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build an AngularJS app&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;todoList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addTodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="nx"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todoText&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todoText&lt;/span&gt; &lt;span class="o"&gt;=&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While Angular was the last of the three mentioned here, it had a huge impact. It was the first time Google released a JavaScript-based MVC based library into the wild.&lt;/p&gt;

&lt;p&gt;Not only did they build the library, &lt;a href="https://www.youtube.com/watch?v=r1A1VR0ibIQ" rel="noopener noreferrer"&gt;they used it to build Google’s Feedback tool&lt;/a&gt; - which powers almost all of Google’s products today. This represented a shift from their prior Java-based “&lt;a href="http://www.gwtproject.org/" rel="noopener noreferrer"&gt;Google Web Toolkit” (GWT)&lt;/a&gt; that was widely used before.&lt;/p&gt;

&lt;p&gt;Later, with the &lt;a href="https://www.nytimes.com/2007/04/14/technology/14DoubleClick.html" rel="noopener noreferrer"&gt;acquisition of DoubleClick&lt;/a&gt;, the team that was working on the &lt;a href="https://www.youtube.com/watch?v=r1A1VR0ibIQ" rel="noopener noreferrer"&gt;migration of the DoubleClick platform for Google decided to use Angular.js as well&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  2011: A Glimmer in W3C Standard’s Eye
&lt;/h1&gt;

&lt;p&gt;With Angular.js continuing to grow within Google, it’s no surprise that they continued researching in-JavaScript HTML bindings.&lt;/p&gt;

&lt;p&gt;On this topic, Alex Russel - then a Senior Staff Engineer at Google, working on the web platform team - &lt;a href="https://fronteers.nl/congres/2011/sessions/web-components-and-model-driven-views-alex-russell" rel="noopener noreferrer"&gt;gave a talk at the Fronteers conference&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this talk, he introduces a host of libraries that allow building custom elements with experimental new APIs.&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;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Comment&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attrs&lt;/span&gt; &lt;span class="o"&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;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attrs&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;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attrs&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;||&lt;/span&gt; &lt;span class="nx"&gt;lorem&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;shadow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ShadowRoot&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;buildUI&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;buildUI&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="nx"&gt;HTMLElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&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-comment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Howdy, pardner!&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="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&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;x-comment&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/x-comment&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, he utilized the &lt;a href="https://web.archive.org/web/20210311050620/https://github.com/google/traceur-compiler" rel="noopener noreferrer"&gt;TraceUR compiler&lt;/a&gt; (a precursor to Babel) to add classes (remember, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes" rel="noopener noreferrer"&gt;&lt;code&gt;class&lt;/code&gt; wouldn’t land in JavaScript stable until ES6 in 2015&lt;/a&gt;) to build a new “custom element”.&lt;/p&gt;

&lt;p&gt;This combined with their &lt;a href="https://web.archive.org/web/20110509081454/http://code.google.com/p/mdv" rel="noopener noreferrer"&gt;new MDV library&lt;/a&gt; in order to create a similar development environment to what we have in browser APIs today. &lt;/p&gt;

&lt;p&gt;It’s important to note that at this stage, nothing was formalized inside of a specification - It was all experimental libraries acting as playgrounds for APIs.&lt;/p&gt;

&lt;p&gt;That would change soon after.&lt;/p&gt;

&lt;h1&gt;
  
  
  2013: Things Start Heating Up
&lt;/h1&gt;

&lt;p&gt;In early 2013 the Google team created a &lt;a href="https://web.archive.org/web/20130608123733/http://www.w3.org/TR/custom-elements/" rel="noopener noreferrer"&gt;Working Draft of a specification for Custom Elements&lt;/a&gt;. Alongside similar working drafts for Shadow DOM APIs, they were colloquially called “&lt;a href="https://www.html5rocks.com/en/tutorials/webcomponents/customelements/" rel="noopener noreferrer"&gt;Custom Elements v0&lt;/a&gt;”.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://googleblog.blogspot.com/2008/09/fresh-take-on-browser.html" rel="noopener noreferrer"&gt;Google Chrome’s release in 2008&lt;/a&gt;, they had the ability to quickly implement these non-standard APIs into Chrome in order to allow application developers to utilize them before specification stabilization.&lt;/p&gt;

&lt;p&gt;One such example of this was &lt;a href="https://web.archive.org/web/20130515211406/http://www.polymer-project.org/" rel="noopener noreferrer"&gt;Polymer, which was a component library based on v0 APIs to provide two-way UI binding using MVC.&lt;/a&gt; It’s initial alpha release was announced in early 2013, alongside the specifications.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://www.youtube.com/watch?v=DH1vTVkqCDQ" rel="noopener noreferrer"&gt;Google Dev Summit 2013, they walked through its capabilities &lt;/a&gt;and how it was able to run in other browsers by utilizing polyfills.&lt;/p&gt;




&lt;p&gt;Facebook, not one to be outdone on the technical engineering front, &lt;a href="https://www.youtube.com/watch?v=GW0rj4sNH2w" rel="noopener noreferrer"&gt;introduced React into public in 2013&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While Polymer went deeper into the MVC route, &lt;a href="https://coderpad.io/blog/master-react-unidirectional-data-flow/" rel="noopener noreferrer"&gt;React relied more heavily on unidirectionality&lt;/a&gt; in order to avoid state mutations.&lt;/p&gt;

&lt;h1&gt;
  
  
  2016 &amp;amp; 2017: Formative Years
&lt;/h1&gt;

&lt;p&gt;While only the year prior, Polymer 1.0 was released with the usage of v0 custom element spec, &lt;a href="https://web.archive.org/web/20161030051600/http://w3c.github.io/webcomponents/spec/custom/" rel="noopener noreferrer"&gt;2016 saw the release of the custom element v1 specification&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This new version of the specification was not backwards compatible, and as a result required a shift to the new version of the specification in order to function properly. Polyfills were continued to be used as a stop-gate for browsers that didn’t have a v0 implementation.&lt;/p&gt;

&lt;p&gt;While &lt;a href="https://web.archive.org/web/20161101052413/http://caniuse.com/#feat=custom-elementsv1" rel="noopener noreferrer"&gt;v1 was already implemented into Chrome in late 2016&lt;/a&gt;, it wasn’t until 2017 with the release of Polymer 2.0 that it would be adopted back into the library that helped draft the specification.&lt;/p&gt;

&lt;p&gt;Because of this, while &lt;a href="https://blog.youtube/news-and-events/a-sneak-peek-at-youtubes-new-look-and/" rel="noopener noreferrer"&gt;YouTube’s new Polymer rewrite&lt;/a&gt; theoretically was a huge step towards the usage of web components, it posed a problem. Browsers like &lt;a href="https://web.archive.org/web/20180724154806/https://twitter.com/cpeterso/status/1021626510296285185" rel="noopener noreferrer"&gt;Firefox without a v0 implementation were forced to continue to use Polyfills&lt;/a&gt;, which are slower than native implementations.&lt;/p&gt;

&lt;h1&gt;
  
  
  2018 and Beyond: Maturity
&lt;/h1&gt;

&lt;p&gt;2018 is where Web Components really found their foothold.&lt;/p&gt;

&lt;p&gt;For a start, &lt;a href="https://www.mozilla.org/en-US/firefox/63.0/releasenotes/" rel="noopener noreferrer"&gt;Mozilla implemented the v1 specification APIs into their stable release of Firefox&lt;/a&gt;, complete with dedicated devtools. Finally, developers could use all of the web components’ APIs in their app, cross-browser, and without any concern for non-Chrome performance.&lt;/p&gt;

&lt;p&gt;On top of that, React’s unidirectionality seemed to have won over the Polymer team. The Polymer team announced that it would &lt;a href="https://www.polymer-project.org/blog/2018-05-02-roadmap-update#libraries" rel="noopener noreferrer"&gt;migrate away from bidirectional binding and towards a one-way bound &lt;code&gt;LitElement&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That &lt;code&gt;LitElement&lt;/code&gt; would then turn into a dedicated framework called “&lt;a href="https://coderpad.io/blog/web-components-101-lit-framework/" rel="noopener noreferrer"&gt;Lit&lt;/a&gt;”, developed to replace Polymer as its successor, that would hit &lt;a href="https://github.com/lit/lit/releases/tag/v1.0.0" rel="noopener noreferrer"&gt;v1 in 2019&lt;/a&gt; and &lt;a href="https://github.com/lit/lit/releases/tag/lit%402.0.0" rel="noopener noreferrer"&gt;v2 in 2021&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Timeline
&lt;/h1&gt;

&lt;p&gt;Whew! That’s a lot to take in. Let’s see it all from a thousand foot view:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;2010: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/knockout/knockout/releases/tag/v1.0.0" rel="noopener noreferrer"&gt;Knockout.js released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jashkenas/backbone/releases/tag/0.1.0" rel="noopener noreferrer"&gt;Backbone.js alpha released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.archive.org/web/20100413141437/http://getangular.com/" rel="noopener noreferrer"&gt;Angular.js made open-source&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2011:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fronteers.nl/congres/2011/sessions/web-components-and-model-driven-views-alex-russell" rel="noopener noreferrer"&gt;MDV (Polymer predecessor) introduced at a conference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2013:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web.archive.org/web/20130608123733/http://www.w3.org/TR/custom-elements/" rel="noopener noreferrer"&gt;Working draft spec for Web Components (v0) released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=DH1vTVkqCDQ" rel="noopener noreferrer"&gt;Polymer (Google’s web component framework) announced&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GW0rj4sNH2w" rel="noopener noreferrer"&gt;React open-sourced&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2015:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web.archive.org/web/20150814004009/https://www.polymer-project.org/1.0/" rel="noopener noreferrer"&gt;Polymer 1.0 released&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2016:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web.archive.org/web/20161030051600/http://w3c.github.io/webcomponents/spec/custom/" rel="noopener noreferrer"&gt;Custom elements v1 spec released&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.youtube/news-and-events/a-sneak-peek-at-youtubes-new-look-and/" rel="noopener noreferrer"&gt;YouTube rewritten in Polymer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2017:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Polymer/polymer/releases/tag/v2.0.0" rel="noopener noreferrer"&gt;Polymer 2.0 released&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2018:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.polymer-project.org/blog/2018-05-02-roadmap-update#libraries" rel="noopener noreferrer"&gt;Polymer announces start of migration to “LitElement”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mozilla.org/en-US/firefox/63.0/releasenotes/" rel="noopener noreferrer"&gt;Firefox enables web components (Polyfills no longer needed)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2019:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/lit/lit/releases/tag/v1.0.0" rel="noopener noreferrer"&gt;Lit framework 1.0 released&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2021&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/lit/lit/releases/tag/lit%402.0.0" rel="noopener noreferrer"&gt;Lit 2.0 released&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In the past 10 years we’ve seen massive changes to the web development ecosystem. No more is this more apparent than the development and continued growth of web components.&lt;/p&gt;

&lt;p&gt;Hopefully this should put any future learnings about web components and &lt;a href="https://coderpad.io/blog/web-components-101-framework-comparison/" rel="noopener noreferrer"&gt;framework comparisons&lt;/a&gt; into perspective.&lt;/p&gt;

&lt;p&gt;We’ve waited a long time to see many of these ideas fully standardized into the web platform, and, now that they’re here, they’re helping accelerate growth of many platforms.&lt;/p&gt;

&lt;p&gt;Want to learn how to build them yourself?&lt;/p&gt;

&lt;p&gt;We have articles about how to build web components &lt;a href="https://coderpad.io/blog/intro-to-web-components-vanilla-js/" rel="noopener noreferrer"&gt;without a framework&lt;/a&gt; as well as using &lt;a href="https://coderpad.io/blog/web-components-101-lit-framework/" rel="noopener noreferrer"&gt;Google’s Lit framework&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>html</category>
      <category>programming</category>
    </item>
    <item>
      <title>Web Components 101: Framework Comparison</title>
      <dc:creator>CoderPad Team</dc:creator>
      <pubDate>Mon, 04 Apr 2022 17:30:40 +0000</pubDate>
      <link>https://forem.com/coderpad/web-components-101-framework-comparison-989</link>
      <guid>https://forem.com/coderpad/web-components-101-framework-comparison-989</guid>
      <description>&lt;p&gt;Alright alright, I know for a lot of the last article seemed like a big ad for Lit. That said, I promise I’m not unable to see the advantages of other frameworks. Lit is a tool in a web developer’s toolbox. Like any tool, it has its pros and cons: times when it’s the right tool for the job, and other times when it’s less so.&lt;/p&gt;

&lt;p&gt;That said, I’d argue that using an existing framework is more often the better tool for the job than vanilla web components. &lt;/p&gt;

&lt;p&gt;To showcase this, let’s walk through some of these frameworks and compare and contrast them to home-growing web components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros and Cons of Vanilla Web Components
&lt;/h2&gt;

&lt;p&gt;While web frameworks are the hot new jazz - it’s not like we couldn’t make web applications before them. With the advent of W3C standardized web components (without Lit), doing so today is better than it’s ever been.&lt;/p&gt;

&lt;p&gt;Here are some pros and cons of Vanilla JavaScript web components:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No framework knowledge required&lt;/li&gt;
&lt;li&gt;Less reliance on framework&lt;/li&gt;
&lt;li&gt;Maintenance&lt;/li&gt;
&lt;li&gt;Bugs&lt;/li&gt;
&lt;li&gt;Security issues&lt;/li&gt;
&lt;li&gt;Smaller “hello world” size&lt;/li&gt;
&lt;li&gt;More control over render behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Re-rendering un-needed elements is slow&lt;/li&gt;
&lt;li&gt;Handling event passing is tricky&lt;/li&gt;
&lt;li&gt;Creating elements can be overly verbose&lt;/li&gt;
&lt;li&gt;Binding to props requires element query&lt;/li&gt;
&lt;li&gt;You’ll end up building Lit, anyway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To the vanilla way of doing things’ credit, there’s a bit of catharsis knowing that you’re relying on a smaller pool of upstream resources. There’s also a lessened likelihood of some bad push to NPM from someone on the Lit team breaking your build.&lt;/p&gt;

&lt;p&gt;Likewise - for smaller apps - you’re likely to end up with a smaller output bundle. That’s a huge win!&lt;/p&gt;

&lt;p&gt;For smaller applications where performance is critical, or simply for the instances where you need to be as close to the DOM as possible, vanilla web components can be the way to go.&lt;/p&gt;

&lt;p&gt;That said, it’s not all roses. After all, this series has already demonstrated that things like event passing and prop binding are verbose compared to Lit. Plus, things may not be as good as they seem when it comes to performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incremental Rendering
&lt;/h3&gt;

&lt;p&gt;On top of the aforementioned issues with avoiding a framework like Lit, something we haven’t talked about much is incremental rendering. A great example of this would come into play if we had an array of items we wanted to render, and weren’t using Lit. &lt;/p&gt;

&lt;p&gt;Every time we needed to add a single item to that list, our &lt;code&gt;innerHTML&lt;/code&gt; trick would end up constructing a new element for every single item in the list. What’s worse is that every subelement would render as well!&lt;/p&gt;

&lt;p&gt;This means that if you have an element like this:&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;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;”https://example.com”&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;”flex&lt;/span&gt; &lt;span class="na"&gt;p-12&lt;/span&gt; &lt;span class="na"&gt;bg-yellow&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;span&amp;gt;&lt;/span&gt;Go to this location&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And only needed to update the text for a single item in the list, you’d end up creating 4 more elements for the item you wanted to update… On top of recreating the 5 nodes (including the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Text" rel="noopener noreferrer"&gt;Text Node&lt;/a&gt;) for every other item in the list.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building Your Own Framework
&lt;/h3&gt;

&lt;p&gt;As a result of the downsides mentioned, many that choose to utilize vanilla web components often end up bootstrapping their own home-grown version of Lit.&lt;/p&gt;

&lt;p&gt;Here’s the problem with that: You’ll end up writing Lit yourself, sure, but with none of the upsides of an existing framework.&lt;/p&gt;

&lt;p&gt;This is the problem with diving headlong into vanilla web components on their own. Even in our small examples in the article dedicated to vanilla web components, we emulated many of the patterns found within Lit. Take this code from the article:&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="nf"&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="nf"&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;// This function can be accessed in element query to set internal data externally&lt;/span&gt;
    &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&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;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&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="nf"&gt;clear&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="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for &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;child&lt;/span&gt; &lt;span class="k"&gt;of&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;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&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="nf"&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="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="c1"&gt;// Do logic&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="nf"&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-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we’re writing our own &lt;code&gt;clear&lt;/code&gt; logic, handling dynamic value updates, and more.&lt;/p&gt;

&lt;p&gt;The obvious problem is that we’d then have to copy and paste most of this logic in many components in our app. But let’s say that we were dedicated to this choice, and broke it out into a class that we could then extend.&lt;/p&gt;

&lt;p&gt;Heck, let’s even add in some getters and setters to make managing state easier:&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// Base.js&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OurBaseComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&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="nf"&gt;doRender&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&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;// This introduces bugs&lt;/span&gt;
            &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
            &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeData&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&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="nf"&gt;changeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;callback&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="nf"&gt;clear&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="nf"&gt;doRender&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for &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;child&lt;/span&gt; &lt;span class="k"&gt;of&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;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&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="nf"&gt;doRender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callback&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="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;callback&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our usage should look fairly simple!&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// MainFile.js&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;OurBaseComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]});&lt;/span&gt;

    &lt;span class="nf"&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="nf"&gt;doRender&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;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="s2"&gt;`&amp;lt;h1&amp;gt;You have &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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; todos&amp;lt;/h1&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="nf"&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-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s only 13 lines to declare a UI component!&lt;/p&gt;

&lt;p&gt;Only now you have a bug with namespace collision of state with underscores, your &lt;code&gt;doRender&lt;/code&gt; doesn’t handle async functions, and you still have many of the downsides listed below!&lt;/p&gt;

&lt;p&gt;You could work on fixing these, but ultimately, you’ve created a basis of what Lit looks like today, but now you’re starting at square one. No ecosystem on your side, no upstream maintainers to lean on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros and Cons of Lit Framework
&lt;/h2&gt;

&lt;p&gt;With the downsides (and upsides) of vanilla web components in mind, let’s compare the pros and cons of what building components using Lit looks like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster re-renders* that are automatically handled&lt;/li&gt;
&lt;li&gt;More consolidated UI/logic&lt;/li&gt;
&lt;li&gt;More advanced tools after mastery&lt;/li&gt;
&lt;li&gt;Smaller footprint than other frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Framework knowledge required&lt;/li&gt;
&lt;li&gt;Future breaking changes&lt;/li&gt;
&lt;li&gt;Not as widely known/used as other frameworks (Vue, React, Angular)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While there is some overlap between this list of pros and cons and the one for avoiding Lit in favor of home-growing, there’s a few other items here.&lt;/p&gt;

&lt;p&gt;Namely, this table highlights the fact that Lit isn’t the only framework for building web components. There’s huge alternatives like React, Vue, and Angular. These ecosystems have wider adoption and knowledge than Lit, which may make training a team to use Lit more difficult.&lt;/p&gt;

&lt;p&gt;However, Lit has a key advantage over them, ignoring being able to output to web components for a moment - we’ll come back to that.&lt;/p&gt;

&lt;p&gt;Even compared to other frameworks, Lit is uniquely lightweight.&lt;/p&gt;

&lt;p&gt;Compare the bundle sizes of Vue - a lightweight framework in it’s own right - compared to Lit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bundlephobia.com/scan-results?packages=vue@3.2.14,lit@2.0.0" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F12%2Fimg_61a943cd4417d.png" alt="Lit weighs in at 16.3 kilobytes while Vue weighs in at 91.9 kilobytes"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While tree shaking will drastically reduce the bundle size of Vue for smaller applications, Lit will still likely win out for a simple component system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Frameworks
&lt;/h2&gt;

&lt;p&gt;Lit framework isn’t alone in being able to output to web components, however. In recent years, other frameworks have explored and implemented various methods of writing code for a framework that outputs to web components.&lt;/p&gt;

&lt;p&gt;For example, the following frameworks have official support for creating web components without changing implementation code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://v3.vuejs.org/guide/web-components.html#definecustomelement" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://angular.io/guide/elements" rel="noopener noreferrer"&gt;Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/preactjs/preact-custom-element" rel="noopener noreferrer"&gt;Preact&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vue 3, in particular, has made massive strides in improving the web component development experience for their users.&lt;/p&gt;

&lt;p&gt;What’s more is that these tools tend to have significantly larger ecosystems. Take Vue for example.&lt;/p&gt;

&lt;p&gt;Want the ability to change pages easily? &lt;a href="https://router.vuejs.org/" rel="noopener noreferrer"&gt;Vue Router&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want a global store solution? &lt;a href="https://vuex.vuejs.org/" rel="noopener noreferrer"&gt;Vuex&lt;/a&gt;Prefer similar class based components? &lt;a href="https://class-component.vuejs.org/" rel="noopener noreferrer"&gt;Vue Class Component Library&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Prebuilt UI components? &lt;a href="https://www.antdv.com/docs/vue/introduce/" rel="noopener noreferrer"&gt;Ant Design&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While some ecosystem tools might exist in Lit, they certainly don’t have the same breadth.&lt;/p&gt;

&lt;p&gt;That’s not to say it’s all good in the general web component ecosystem. Some frameworks, like React, &lt;a href="https://custom-elements-everywhere.com/" rel="noopener noreferrer"&gt;have issues with Web Component interop&lt;/a&gt;, that may impact your ability to merge those tools together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Web Components?
&lt;/h2&gt;

&lt;p&gt;You may be asking - if you’re going to use a framework like Vue or React anyway, why even bother with web components? Couldn’t you instead write an app in one of those frameworks, without utilizing web components?&lt;/p&gt;

&lt;p&gt;You absolutely can, and to be honest - this is how most apps that use these frameworks are built.&lt;/p&gt;

&lt;p&gt;But web components play a special role in companies that have multiple different projects: Consolidation.&lt;/p&gt;

&lt;p&gt;Let’s say that you work for BigCorp - the biggest corporation in Corpville.&lt;/p&gt;

&lt;p&gt;BigCorp has dozens and dozens of full-scale applications, and not all of them are using the same frontend framework. This might sound irresponsible of BigCorp’s system architects, but in reality, sometimes a framework is better geared towards specific applications. Additionally, maybe some of the apps were part of an acquisition or merger that brought them into the company.&lt;/p&gt;

&lt;p&gt;After all, the user doesn’t care (or often, know) about what framework a tool is built with. You know what a user does care about? The fact that each app in a collection all have vastly different UIs and buttons.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F12%2Fimg_61a943cea067b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F12%2Fimg_61a943cea067b.png" alt="Two different apps, each with different text cutoff points in their button's text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While this is clearly a bug, if both codebases implement the buttons on their own, you’ll inevitably end up with these types of problems; this being on top of the work-hours your teams have to spend redoing one-another’s work for their respective frameworks.&lt;/p&gt;

&lt;p&gt;And that’s all ignoring how difficult it can be to get designers to have consistency between different project’s design components - like buttons.&lt;/p&gt;

&lt;p&gt;Web Components solve this problem.&lt;/p&gt;

&lt;p&gt;If you build a shared component system that exports web components, you can then use the same codebase across multiple frameworks.&lt;/p&gt;

&lt;p&gt;Once the code is written and exported into web components, it’s trivial to utilize these new web components in your application. Like, it can be a &lt;a href="https://v3.vuejs.org/guide/web-components.html#tips-for-a-vue-custom-elements-library" rel="noopener noreferrer"&gt;single line of code trivial.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From this point, you’re able to make sure the logic and styling of these components are made consistent between applications - even if different frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;While web components have had a long time in the oven, they came out swinging! And while Lit isn’t the only one at the table, they’ve certainly found a strong foothold in capabilities.&lt;/p&gt;

&lt;p&gt;Lit’s lightweightness, paired with web component’s abilities to integrate between multiple frameworks is an incredible one-two punch that makes it a strong candidate for any shared component system.&lt;/p&gt;

&lt;p&gt;What’s more, the ability to transfer knowledge from other frameworks makes it an easy tool to place in your toolbox for usage either now or in the future.&lt;/p&gt;

&lt;p&gt;Regardless; whether you’re using Vue, React, Angular, Lit, Vanilla Web Components, or anything else, we wish you happy engineering!&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>vue</category>
      <category>react</category>
      <category>angular</category>
    </item>
    <item>
      <title>Why React 18 Broke Your App</title>
      <dc:creator>CoderPad Team</dc:creator>
      <pubDate>Thu, 31 Mar 2022 21:32:17 +0000</pubDate>
      <link>https://forem.com/coderpad/why-react-18-broke-your-app-4730</link>
      <guid>https://forem.com/coderpad/why-react-18-broke-your-app-4730</guid>
      <description>&lt;p&gt;You’ve just gotten done with &lt;a href="https://coderpad.io/blog/how-to-upgrade-to-react-18/"&gt;your React 18 upgrade&lt;/a&gt;, and, after some light QA testing, don’t find anything. “An easy upgrade,” you think.&lt;/p&gt;

&lt;p&gt;Unfortunately, down the road, you receive some internal bug reports from other developers that make it sound like your debounce hook isn’t working quite right. You decide to make a minimal reproduction and create a demo of said hook.&lt;/p&gt;

&lt;p&gt;You expect it to throw an “alert” dialog after a second of waiting, but weirdly, the dialog never runs at all.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=200065"&gt;See and run the related code sample in the sandbox&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is strange because it was working just last week on your machine! Why did this happen? What changed?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The reason your app broke in React 18 is that you’re using &lt;code&gt;StrictMode&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Simply go into your &lt;code&gt;index.js&lt;/code&gt; (or &lt;code&gt;index.ts&lt;/code&gt;) file, and change this bit of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To read like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of the bugs that were seemingly introduced within your app in React 18 are suddenly gone.&lt;/p&gt;

&lt;p&gt;Only one problem: These bugs are real and existed in your codebase before React 18 - you just didn’t realize it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Proof of broken component
&lt;/h2&gt;

&lt;p&gt;Looking at our example from before, we’re using &lt;a href="https://coderpad.io/blog/how-to-upgrade-to-react-18/"&gt;React 18’s &lt;code&gt;createRoot&lt;/code&gt; API&lt;/a&gt; to render our &lt;code&gt;App&lt;/code&gt; inside of a &lt;code&gt;StrictMode&lt;/code&gt; wrapper in lines 56 - 60.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=200065"&gt;See and run the related code sample in the sandbox&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Currently, when you press the button, it doesn’t do anything. However, if you remove the &lt;/p&gt;

&lt;p&gt;&lt;code&gt;StrictMode&lt;/code&gt; and reload the page, you can see an &lt;code&gt;Alert&lt;/code&gt; after a second of being debounced.&lt;/p&gt;

&lt;p&gt;Looking through the code, let’s add some &lt;code&gt;console.log&lt;/code&gt;s into our &lt;code&gt;useDebounce&lt;/code&gt;, since that’s where our function is supposed to be called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useDebounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&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;inputsRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&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;isMounted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useIsMounted&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useEffect&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;inputsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&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="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;((...&lt;/span&gt;&lt;span class="nx"&gt;args&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Before function is called&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;inputsRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isMounted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isMounted&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;inputsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isMounted&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="s2"&gt;After function is called&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                  &lt;span class="nx"&gt;inputsRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;delay&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;blockquote&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before function is called Object { inputsRef: {…}, delay: 1000, isMounted: false }
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;Oh! It seems like &lt;code&gt;isMounted&lt;/code&gt; is never being set to true, and therefore the &lt;code&gt;inputsRef.current&lt;/code&gt; callback is not being called: that’s our function we wanted to be debounced.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the &lt;code&gt;useIsMounted()&lt;/code&gt; codebase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useIsMounted&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;isMountedRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useRef&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="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useEffect&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;isMountedRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;isMountedRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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;This code, at first glance, makes sense. After all, while we’re doing a cleanup in the return function of &lt;code&gt;useEffect&lt;/code&gt; to remove it at first render, &lt;code&gt;useRef&lt;/code&gt;'s initial setter runs at the start of each render, right?&lt;/p&gt;

&lt;p&gt;Well, not quite.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed in React 18?
&lt;/h2&gt;

&lt;p&gt;In older versions of React, you would mount a component once and that would be it. As a result, the initial value of &lt;code&gt;useRef&lt;/code&gt; and &lt;code&gt;useState&lt;/code&gt; could almost be treated as if they were set once and then forgotten about.&lt;/p&gt;

&lt;p&gt;In React 18, the React developer team decided to change this behavior and &lt;a href="https://github.com/reactwg/react-18/discussions/19"&gt;re-mount each component more than once in strict mode&lt;/a&gt;. This is in strong part due to the fact that a potential future React feature will have exactly that behavior.&lt;/p&gt;

&lt;p&gt;See, one of the features that the React team is hoping to add in a future release utilizes a concept of “&lt;a href="https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state"&gt;reusable state&lt;/a&gt;”. The general idea behind reusable state is such that if you have a tab that’s un-mounted (say when the user tabs away), then re-mounted (when the user tabs back), React will recover the data that was assigned to said tab component. This data being immediately available allows you to render the respective component immediately without hesitation.&lt;/p&gt;

&lt;p&gt;Because of this, while data inside of, say, &lt;code&gt;useState&lt;/code&gt; may be persisted, it’s imperative that effects are properly cleaned up and handled properly. &lt;a href="https://reactjs.org/docs/strict-mode.html#ensuring-reusable-state"&gt;To quote the React docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This feature will give React better performance out-of-the-box but requires components to be resilient to effects being mounted and destroyed multiple times.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, this behavior shift in Strict Mode within React 18 isn’t just protective future-proofing from the React team: it’s also a reminder to follow React’s rules properly and to clean up your actions as expected.&lt;/p&gt;

&lt;p&gt;After all, the &lt;a href="https://reactjs.org/docs/hooks-reference.html#usememo"&gt;React team themselves have been warning that an empty dependent array&lt;/a&gt; (&lt;code&gt;[]&lt;/code&gt; as the second argument) should not guarantee that it only runs once for ages now.&lt;/p&gt;

&lt;p&gt;In fact, this article may be a bit of a misnomer - &lt;a href="https://github.com/reactwg/react-18/discussions/19#discussioncomment-796197="&gt;the React team says they’ve upgraded thousands of components in Facebook’s core codebase without significant issues&lt;/a&gt;. More than likely, a majority of applications out there will be able to upgrade to the newest version of React without any problems. &lt;/p&gt;

&lt;p&gt;All that said, these React missteps crawl their way into our applications regardless. While the React team may not anticipate many breaking apps, these errors seem relatively common enough to warrant an explanation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to fix the remounting bug
&lt;/h2&gt;

&lt;p&gt;The code I linked before was written by me in a production application and it's wrong. Instead of relying on &lt;code&gt;useRef&lt;/code&gt; to initialize the value once, we need to ensure the initialization runs on every instance of &lt;code&gt;useEffect&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useIsMounted&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;isMountedRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useRef&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="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useEffect&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;isMountedRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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;// Added this line  &lt;/span&gt;
  &lt;span class="k"&gt;return&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;isMountedRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;isMountedRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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;This is true for the inverse as well! We need to make sure to run cleanup on any components that we may have forgotten about before.&lt;/p&gt;

&lt;p&gt;Many ignore this rule for &lt;code&gt;App&lt;/code&gt; and other root elements that they don’t intend to re-mount, but with new strict mode behaviors, that guarantee is no longer a safe bet.&lt;/p&gt;

&lt;p&gt;To solve this application across your app, look for the following signs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Side effects with cleanup but no setup (like our example)&lt;/li&gt;
&lt;li&gt;A side effect without proper cleanup&lt;/li&gt;
&lt;li&gt;Utilizing &lt;code&gt;[]&lt;/code&gt; in &lt;code&gt;useMemo&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; to assume that said code will only run once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One this code is eliminated, you should be back to a fully functioning application and can re-enable StrictMode in your application!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;React 18 brings many amazing features to the table, such as &lt;a href="https://reactjs.org/docs/concurrent-mode-suspense.html"&gt;new suspense features&lt;/a&gt;, &lt;a href="https://github.com/reactwg/react-18/discussions/111"&gt;the new useId hook&lt;/a&gt;, &lt;a href="https://github.com/reactwg/react-18/discussions/21"&gt;automatic batching&lt;/a&gt;, and more. While refactor work to support these features may be frustrating at times, it’s important to remember that they a serve real-world benefit to the user.&lt;/p&gt;

&lt;p&gt;For example, React 18 also introduces some functionality to debounce renders in order to create a much nicer experience when rapid user input needs to be processed.&lt;/p&gt;

&lt;p&gt;For more on the React 18 upgrade process, take a look at &lt;a href="https://coderpad.io/blog/how-to-upgrade-to-react-18/"&gt;our instruction guide on how to upgrade to React 18&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>react18</category>
      <category>programming</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Web Components 101: Lit Framework</title>
      <dc:creator>CoderPad Team</dc:creator>
      <pubDate>Mon, 28 Mar 2022 16:46:08 +0000</pubDate>
      <link>https://forem.com/coderpad/web-components-101-lit-framework-3en1</link>
      <guid>https://forem.com/coderpad/web-components-101-lit-framework-3en1</guid>
      <description>&lt;p&gt;Recently we talked about &lt;a href="https://coderpad.io/blog/intro-to-web-components-vanilla-js/"&gt;what web components are and how you can build a web app utilizing them with only vanilla JavaScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While web components are absolutely usable with only vanilla JavaScript, more complex usage, especially pertaining to value binding, can easily become unwieldy.&lt;/p&gt;

&lt;p&gt;One potential solution might be using a web component framework such as VueJS or React. However, web-standard components can still be a massive boon to development.&lt;/p&gt;

&lt;p&gt;As such, there’s a framework called &lt;a href="https://lit.dev/"&gt;“Lit”&lt;/a&gt; that is developed specifically to leverage web components. With &lt;a href="https://lit.dev/blog/2021-09-21-announcing-lit-2/"&gt;Lit 2.0 recently launching as a stable release&lt;/a&gt;, we thought we’d take a look at how we can simplify web component development.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTML
&lt;/h2&gt;

&lt;p&gt;One of the greatest strengths of custom elements is the ability to contain multiple other elements. This makes it so that you can have custom elements for every scale: from a button to an entire page.&lt;/p&gt;

&lt;p&gt;To do this in a vanilla JavaScript custom element, you can use &lt;code&gt;innerHTML&lt;/code&gt; to create new child elements.&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;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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="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;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;p&amp;gt;Hello!&amp;lt;/p&amp;gt;&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;hello-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;hello-component&amp;gt;&amp;lt;/hello-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This initial example looks fairly similar to what the Lit counterpart of that code looks like:&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;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.skypack.dev/lit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HelloElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LitElement&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;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
              &amp;lt;p&amp;gt;Hello!&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="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="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;hello-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HelloElement&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;hello-component&amp;gt;&amp;lt;/hello-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=194516"&gt;Run this code sample in an interactive playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are two primary differences from the vanilla JavaScript example. First, we no longer need to use the &lt;code&gt;connectedCallback&lt;/code&gt; to call &lt;code&gt;render&lt;/code&gt;. The LitElement’s &lt;code&gt;render&lt;/code&gt; function is called by Lit itself whenever needed - such as when data changes or for an initial render - avoiding the need to manually re-call the render method. &lt;/p&gt;

&lt;p&gt;That said, Lit components fully support the same lifecycle methods as a vanilla custom elements.&lt;/p&gt;

&lt;p&gt;The second, easier-to-miss change from the vanilla JavaScript component to the Lit implementation, is that when we set our HTML, we don’t simply use a basic template literal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`&amp;lt;p&amp;gt;test&amp;lt;/p&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We pass the function &lt;code&gt;html&lt;/code&gt; to the template literal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;html`&amp;lt;p&amp;gt;test&amp;lt;/p&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This leverages &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates"&gt;a somewhat infrequently used feature of template literals called tagged templates&lt;/a&gt;. Tagged templates allow a template literal to be passed to a function. This function can then transform the output based on the string input and expected interpolated placeholders.&lt;/p&gt;

&lt;p&gt;Because tagged templates return a value like any other function, you can assign the return value of &lt;code&gt;html&lt;/code&gt; to a variable.&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="nx"&gt;render&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;el&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
            &amp;lt;p&amp;gt;Hello!&amp;lt;/p&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="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;If you were to &lt;code&gt;console.log&lt;/code&gt; this value, you’d notice that it’s not an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement"&gt;HTMLElement&lt;/a&gt;. Instead, it’s a custom value that Lit utilizes to render to proper DOM nodes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event Binding
&lt;/h2&gt;

&lt;p&gt;“If the syntax is so similar, why would I add a framework to build custom elements?”&lt;/p&gt;

&lt;p&gt;Well, while the Vanilla JavaScript and Lit custom element code look similar for a small demo: The story changes dramatically when you look to scale up.&lt;/p&gt;

&lt;p&gt;For example, if you wanted to render a button and add a click event to the button with vanilla JavaScript, you’d have to abandon the &lt;code&gt;innerHTML&lt;/code&gt; element assignment method.&lt;/p&gt;

&lt;p&gt;First, we’ll create an element using &lt;code&gt;document.createElement&lt;/code&gt;, then add events, and finally utilize &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/append"&gt;an element method like &lt;code&gt;append&lt;/code&gt;&lt;/a&gt; to add the node to the 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;script&amp;gt;&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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="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;sayHello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hi there!&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;render&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;button&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;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Say Hello!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;button&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;sayHello&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;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;button&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="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="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;hello-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;hello-component&amp;gt;&amp;lt;/hello-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this works for the initial render, it doesn’t handle any of the edgecases that,at scale,can cause long-term damage to your app’s maintainability &amp;amp; performance. &lt;/p&gt;

&lt;p&gt;For example, future re-renders of the element will duplicate the button. To solve this, you must iterate through all of the element’s &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/children"&gt;&lt;code&gt;children&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/remove"&gt;&lt;code&gt;remove&lt;/code&gt;&lt;/a&gt; them one-by-one.&lt;/p&gt;

&lt;p&gt;Further, once the element is removed from the DOM, the click listener is not implicitly removed in the background. Because of this, it’s never released from memory and is considered a memory leak. If this issue continued to occur during long-term usage of your app, it would likely bloat memory usage and eventually crash or hang.&lt;/p&gt;

&lt;p&gt;To solve this, you’d need to assign a variable for every &lt;code&gt;addEventListener&lt;/code&gt; you had present. This may be simple for one or two events, but add too many and it can be difficult to keep track.&lt;/p&gt;

&lt;p&gt;And all of this ignores the maintenance standpoint: What does that code do at a glance?&lt;/p&gt;

&lt;p&gt;It doesn't look anything like HTML and as a result, requires you to consistently context shift between writing standard HTML in a string and using the DOM APIs to construct elements. &lt;/p&gt;

&lt;p&gt;Luckily, Lit doesn’t have these issues. Here’s the same button construction and rendering to a custom element using Lit instead of vanilla JavaScript:&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;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.skypack.dev/lit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HelloElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;sayHello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hi there!&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;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;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
            &amp;lt;button @click=&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;sayHello&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;Say Hello!&amp;lt;/button&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="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="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;hello-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HelloElement&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;hello-component&amp;gt;&amp;lt;/hello-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=194518"&gt;Run this code sample in an interactive playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yup, that’s all. Lit allows you to bind elements by using the &lt;code&gt;@&lt;/code&gt; sign and passing the function as a placeholder to the &lt;code&gt;html&lt;/code&gt; tagged template. Not only does this look much HTML-like, it handles event cleanup, re-rendering, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attributes &amp;amp; Properties
&lt;/h2&gt;

&lt;p&gt;As we learned before, there are two ways to pass values between and into components: attributes and values.&lt;/p&gt;

&lt;p&gt;Previously, when we were using vanilla JavaScript, we had to define these separately. Moreover, we had to declare which attributes to dynamically listen to value changes of.&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;MyComponent&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="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="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;message&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;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;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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&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;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world&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;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Lit, we declare attributes and properties using a static getter and treat them as normal values in any of our functions.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.skypack.dev/lit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HelloElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&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;properties&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&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;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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world&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;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;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;h1&amp;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;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&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="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="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;hello-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HelloElement&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For starters, we no longer have to manually call “render” when a property’s value is changed. Lit will re-render when values are changed.&lt;/p&gt;

&lt;p&gt;That’s not all, though: Keen eyed readers will notice that we’re declaring a type associated with the &lt;code&gt;message&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;Unlike the &lt;a href="https://github.com/facebook/prop-types"&gt;React ecosystem’s PropTypes&lt;/a&gt;, the &lt;code&gt;type&lt;/code&gt; subproperty doesn’t do runtime type validation. Instead, it acts as an automatic type converter.&lt;/p&gt;

&lt;p&gt;This can be of great help as the knowledge that attributes can only be strings can be difficult to remember while debugging.&lt;/p&gt;

&lt;p&gt;For example, we can tell Lit to convert an attribute to a Number and it will migrate from a string that looks like a number to an actual JavaScript type number.&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;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.skypack.dev/lit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HelloElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&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;properties&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="na"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Number&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;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;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;h1&amp;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;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is typeof &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;typeof&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;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&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="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="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;hello-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;HelloElement&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="c"&gt;&amp;lt;!-- This will show "123 is typeof number"  --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;hello-component&lt;/span&gt; &lt;span class="na"&gt;val=&lt;/span&gt;&lt;span class="s"&gt;"123"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/hello-component&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- This will show "NaN is typeof number"  --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;hello-component&lt;/span&gt; &lt;span class="na"&gt;val=&lt;/span&gt;&lt;span class="s"&gt;"Test"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/hello-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=194519"&gt;Run this code sample in an interactive playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Attribute Reactivity
&lt;/h3&gt;

&lt;p&gt;One of the biggest benefits of not having to call &lt;code&gt;render&lt;/code&gt; manually is that Lit is able to render contents when they need to update.&lt;/p&gt;

&lt;p&gt;For example, given this example, the contents will render properly to update with new values.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;ChangeMessageElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&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;properties&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="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&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;changeSelectedMsg&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;newMsg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;msgs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;msgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newMsg&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world&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;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;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;button @click="&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;changeSelectedMsg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;Toggle&amp;lt;/button&amp;gt;
    &amp;lt;hello-component message=&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;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;lt;/hello-component&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=181069"&gt;Run this code sample in an interactive playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Reactive Data Binding
&lt;/h2&gt;

&lt;p&gt;This reactivity comes with its own set of limitations. While numbers and strings are able to be set fairly trivially, objects (and by extension arrays) are a different story.&lt;/p&gt;

&lt;p&gt;This is because, in order for Lit to know what properties to update in render, an object must have a different reference value from one to another. &lt;a href="https://www.coletiv.com/blog/dangers-of-using-objects-in-useState-and-useEffect-ReactJS-hooks/"&gt;This is just how React and other frameworks detect changes in state as well.&lt;/a&gt;&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;FormElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LitElement&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="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&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;properties&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="na"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;inputVal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&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;_onSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;e&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="cm"&gt;/* This works, because we’re changing the object reference */&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;todoList&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;todoList&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;inputVal&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;       &lt;span class="cm"&gt;/* But this would not, because we aren’t */&lt;/span&gt;
      &lt;span class="c1"&gt;// this.todoList.push(this.inputVal);       this.inputVal = '';&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;_onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;inputVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&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;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;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;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;form @submit="&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;_onSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;
      &amp;lt;input .value="&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;inputVal&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" @change="&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;_onChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" type="text" /&amp;gt;
      &amp;lt;button type="submit"&amp;gt;Add&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
    &amp;lt;todo-component todos=&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;todoList&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;lt;/todo-component&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may also notice that we’re binding both the user’s input and output to set and reflect the state. &lt;a href="https://coderpad.io/blog/master-react-unidirectional-data-flow/"&gt;This is exactly how other frameworks like React also expect you to manage user state&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=181090"&gt;Run this code sample in an interactive playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Prop Passing with Lit’s Dot Synax
&lt;/h2&gt;

&lt;p&gt;HTML attributes are not the only way to pass data to a web component. Properties on the element class are a way to pass more than just a string to an element.&lt;/p&gt;

&lt;p&gt;While the &lt;code&gt;type&lt;/code&gt; field can help solve this problem as well, you’re still limited by serializability, meaning that things like functions won’t be able to be passed by attributes.&lt;/p&gt;

&lt;p&gt;While properties are a more robust method of data passing to web components, they’re seldomly used in vanilla JavaScript due to their complexity in coding.&lt;/p&gt;

&lt;p&gt;For example, this is a simple demonstration of passing an array.&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;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Render object array as "ul", passing fn to checkbox change event --&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;MyComponent&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;property&lt;/span&gt; &lt;span class="o"&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;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;h1&amp;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;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&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-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;script&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;changeElement&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;compEl&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;#mycomp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;compEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt; &lt;span class="o"&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;Testing&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;Second&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;Another&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;      
        &lt;span class="nx"&gt;compEl&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="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-component&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"mycomp"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"changeElement()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Change to 3&lt;span class="nt"&gt;&amp;lt;/button&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;p&gt;First, you have to get a reference to the element using an API like &lt;code&gt;querySelector&lt;/code&gt;. This means you need to introduce a new reference to the component and make sure the IDs match in both parts of code.&lt;/p&gt;

&lt;p&gt;Then, just as is the case with updating attribute values, we need to manually call the “render” function in order to update the UI.&lt;/p&gt;

&lt;p&gt;But those complaints aside, there’s still one more: It places your data and component tags in two different areas. Because of this, it can be more difficult to debug or figure out what data is being passed to what component.&lt;/p&gt;

&lt;p&gt;Lit takes a different approach. Within a Lit &lt;code&gt;html&lt;/code&gt; tagged template, add a period before an attribute binding and suddenly it will pass as a property instead.&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;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://cdn.skypack.dev/lit&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;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&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;properties&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="na"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&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;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;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
      &amp;lt;h1&amp;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;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&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="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="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-component&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;class&lt;/span&gt; &lt;span class="nx"&gt;ChangeMessageElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&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;properties&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="na"&gt;array&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&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;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;array&lt;/span&gt; &lt;span class="o"&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;changeElement&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;array&lt;/span&gt; &lt;span class="o"&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;Testing&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;Second&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;Another&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;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;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
      &amp;lt;!-- If "property" didn't have a period, it would pass as attribute --&amp;gt;
      &amp;lt;my-component .property=&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;array&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;lt;/my-component&amp;gt;
      &amp;lt;button @click=&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;changeElement&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;Change to 3&amp;lt;/button&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="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="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;change-message-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ChangeMessageElement&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;change-message-component&amp;gt;&amp;lt;/change-message-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=194520"&gt;Run this code sample in an interactive playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This works because properties and attributes are both created at the same time with Lit.&lt;/p&gt;

&lt;p&gt;However, due to the period binding not being HTML standard, it comes with the side effect of having to use a Lit template in order to bind properties. This tends not to be a problem in applications - since many tend to use and compose components throughout their applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Array Rendering
&lt;/h2&gt;

&lt;p&gt;In our article about vanilla JavaScript web components, we built a simple todo list. Let’s take another look at that example, but this time using Lit for our component code. We’ll get started with a parent &lt;code&gt;FormElement&lt;/code&gt;, which will manage the data and user input.&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;FormElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&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;properties&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="na"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;inputVal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&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;_onSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;e&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todoList&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;todoList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;name&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;inputVal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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;inputVal&lt;/span&gt; &lt;span class="o"&gt;=&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;// ...&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;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;button @click=&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;toggleAll&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;Toggle all&amp;lt;/button&amp;gt;
    &amp;lt;form @submit=&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;_onSubmit&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;
      &amp;lt;input .value=&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;inputVal&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; @change=&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;_onChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; type="text" /&amp;gt;

      &amp;lt;button type="submit"&amp;gt;Add&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
    &amp;lt;!-- Notice the period in ".todos" --&amp;gt;
    &amp;lt;todo-component .todos=&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;todoList&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;lt;/todo-component&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have a form that contains an array, an important question arises: how do we iterate through an array in order to create individual elements for a list?&lt;/p&gt;

&lt;p&gt;Well, while &lt;a href="https://reactjs.org/docs/lists-and-keys.html"&gt;React has &lt;code&gt;Array.map&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://v3.vuejs.org/guide/list.html#mapping-an-array-to-elements-with-v-for"&gt;Vue has &lt;code&gt;v-for&lt;/code&gt;&lt;/a&gt;, Lit uses a &lt;code&gt;repeat&lt;/code&gt; function. Here’s an example:&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;TodoElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&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;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;ul&amp;gt;
      &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;repeat&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;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
        &amp;lt;li&amp;gt;
          &amp;lt;input type="checkbox" .checked=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&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;todo&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;
        &amp;lt;/li&amp;gt;
      `&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
    &amp;lt;/ul&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=181092"&gt;Run this code sample in an interactive playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Passing Functions
&lt;/h2&gt;

&lt;p&gt;Before we step away from code to talk pros and cons about Lit itself (shh, spoilers!); let’s take a look at a code sample that demonstrates many of the benefits over vanilla JavaScript web components we’ve talked about today.&lt;/p&gt;

&lt;p&gt;Readers of the previous blog post will remember that when passing an array of objects to a web component, things looked pretty decent.&lt;/p&gt;

&lt;p&gt;It wasn’t until we tried binding event listeners to an array of objects that things got complex (and messy). Between needing to manually create elements using &lt;code&gt;document&lt;/code&gt;, dealing with &lt;code&gt;querySelector&lt;/code&gt; to pass properties, manually calling “render”, and needing to implement a custom “clear” method - it was a messy experience.&lt;/p&gt;

&lt;p&gt;Let’s see how Lit handles the job.&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;TodoElement&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;LitElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headerText&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;todos&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="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
    &amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;headerText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&amp;gt;
    &amp;lt;ul&amp;gt;
      &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;repeat&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;todos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="s2"&gt;`
        &amp;lt;li&amp;gt;
          &amp;lt;input type="checkbox" @change=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; .checked=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&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;todo&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;
        &amp;lt;/li&amp;gt;
      `&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;
    &amp;lt;/ul&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=181093"&gt;Run this code sample in an interactive playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You will notice that we’re using a &lt;code&gt;filter&lt;/code&gt; within our &lt;code&gt;render&lt;/code&gt; method. Because this logic is within the &lt;code&gt;render&lt;/code&gt; method, it will run on every UI update. This is important to note in case you have expensive operations: you should avoid running those within the render method.&lt;/p&gt;

&lt;p&gt;Outside of this, however - that’s all there is! It reads just like HTML would (with the added benefit of cleanup and prop passing), handles dynamic data, and more!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The ability to leverage Lit in an application makes maintaining and improving a project easier than rolling web components yourself.&lt;/p&gt;

&lt;p&gt;Lit demonstrates significant growth in web components from the early days of &lt;a href="http://polymer-project.org/"&gt;Polymer&lt;/a&gt;. This growth is in no small part due to the Lit team themselves, either!&lt;/p&gt;

&lt;p&gt;Before it was a fully fledged framework, the project started from the &lt;code&gt;lit-html&lt;/code&gt; package, which was an offshoot of Polymer. The Polymer team was instrumental in standardizing the modern variant of web components.&lt;/p&gt;

&lt;p&gt;The ability to use Lit can strongly enhance web component development, but there are other options out there. Next time, we’ll talk about what the competitors are doing, what the pros and cons of each are, and how you can make the best choice for your applications.&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>lit</category>
      <category>programming</category>
    </item>
    <item>
      <title>Web Components 101: Vanilla JavaScript</title>
      <dc:creator>CoderPad Team</dc:creator>
      <pubDate>Thu, 24 Mar 2022 22:19:38 +0000</pubDate>
      <link>https://forem.com/coderpad/web-components-101-vanilla-javascript-2pja</link>
      <guid>https://forem.com/coderpad/web-components-101-vanilla-javascript-2pja</guid>
      <description>&lt;p&gt;Many modern web apps today are built using components. While frameworks like React exist to add an implementation, web components seek to make those practices standardized and part of your browser.&lt;/p&gt;

&lt;p&gt;In this article, we’ll touch on what web components are, how we can build them without a framework, and some limitations to keep in mind during development. Later, in a follow-up article, we’ll show how a lightweight framework (such as Lit) can provide quality-of-life improvements for those looking to build larger scale applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Web Components?
&lt;/h2&gt;

&lt;p&gt;There are a lot of misconceptions about what web components even are. While some might assume that it’s simply the ability to make custom elements with dedicated UI, style, and logic in one consolidated place (more on that later), there’s definitely more to it&lt;/p&gt;

&lt;p&gt;Web components are a mix of 3 different web standards that, when utilized together, can offer a viable alternative to using a framework like React which offers similar functionality. These web standards consist of:&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" rel="noopener noreferrer"&gt;Custom elements&lt;/a&gt; - the ability to create new elements that will provide unique UI and app logic when the related HTML tag is added&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM" rel="noopener noreferrer"&gt;Shadow DOM&lt;/a&gt; - the ability to keep specific elements segmented off from your main document DOM, allowing you to avoid document collision issues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots" rel="noopener noreferrer"&gt;HTML templates&lt;/a&gt; - elements that allow you to write HTML that is not drawn to the page, but can be used as a template for markup to reuse elsewhere&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While the Shadow DOM and HTML templates are undoubtedly useful in applications, we’ll be focusing on custom elements today, as we feel they’re the easiest place to start in introducing web components as a whole.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While these are the only official specifications part of Web Components, they’re often utilized with other JavaScript and browser features to create a cohesive development experience.&lt;/p&gt;

&lt;p&gt;One of these features often used is &lt;a href="https://v8.dev/features/modules" rel="noopener noreferrer"&gt;JavaScript Modules&lt;/a&gt;. While the concept of breaking your app into multiple files has been commonplace with bundlers like Webpack for a while, being built into the browser has been game changing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What are Custom Elements?
&lt;/h2&gt;

&lt;p&gt;At their core, custom elements essentially allow you to create new HTML tags. These tags are then used to implement custom UI and logic that can be used throughout your application.&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="c"&gt;&amp;lt;!-- page.html --&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- These are custom elements, combined to make a page --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;page-header&amp;gt;&amp;lt;/page-header&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;page-contents&amp;gt;&amp;lt;/page-contents&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;page-footer&amp;gt;&amp;lt;/page-footer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These components can be as simple as a styled button or as complex as an entire page of your application, complete with your business logic.&lt;/p&gt;

&lt;p&gt;While we tend to think of HTML tags as directly mapping to a single DOM element, that’s not always the case with custom elements. For example, the “page-header” tag in the example above might contain “nav” and “a” elements as a list of their children.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F07%2Fpasted-image-0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F07%2Fpasted-image-0.png" alt="img"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because of this, we’re able to improve an app’s organization by reducing the amount of tags visible in a single file to read with better flow. &lt;/p&gt;

&lt;p&gt;But custom elements aren’t just made up of HTML - you’re able to associate JavaScript logic with these tags as well! This enables you to keep your logic alongside it’s associated UI. Say your header is a dropdown that’s powered by JavaScript. Now you can keep that JavaScript inside of your “page-header” component, keeping your logic consolidated.&lt;/p&gt;

&lt;p&gt;Finally, a significant improvement that components provide is composability. You’re able to use these components on different pages, allowing you to keep your header code in sync between pages. This reduces the potential for having variations in standard components - like having multiple differently sized buttons in a page - that might confuse your users. As long as you’re vigilant about utilizing your existing components, you’re able to make your app more consistent this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  History
&lt;/h2&gt;

&lt;p&gt;But web components didn’t come from nowhere. While web components enjoy large-scale usage now, that wasn’t always the case. Let’s walk through a short history of web components and the related ecosystem.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2010: 

&lt;ul&gt;
&lt;li&gt;Angular.js made open-source&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2011:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://fronteers.nl/congres/2011/sessions/web-components-and-model-driven-views-alex-russell" rel="noopener noreferrer"&gt;Web components are announced at a conference by Alex Russell&lt;/a&gt; (then Sr Staff Engineer at Google, working on web platform team)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2013:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=DH1vTVkqCDQ" rel="noopener noreferrer"&gt;Polymer (Google’s web component framework) public development began&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GW0rj4sNH2w" rel="noopener noreferrer"&gt;React open-sourced&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2016:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.youtube/news-and-events/a-sneak-peek-at-youtubes-new-look-and/" rel="noopener noreferrer"&gt;YouTube rewritten in Polymer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2018:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.polymer-project.org/blog/2018-05-02-roadmap-update#libraries" rel="noopener noreferrer"&gt;Polymer announces start of migration to “LitElement”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mozilla.org/en-US/firefox/63.0/releasenotes/" rel="noopener noreferrer"&gt;Firefox enables web components (Polyfills no longer needed)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;While JavaScript frameworks with similar concepts have been around since at least 2010, web components have found a way to standardize those concepts in the browser. &lt;/p&gt;

&lt;p&gt;it’s clear that the core concepts at play in web components have allowed for dramatic adoption since then. For example React, which has a lot of the same ideas at play, now has a major market share of websites and applications written in JavaScript. &lt;/p&gt;

&lt;p&gt;Now that we’ve seen a short history of web components, let’s take a look at how to build custom elements without using a framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lifecycle Methods
&lt;/h2&gt;

&lt;p&gt;While many implementations of components have differences, one concept that is fairly universal is “lifecycle methods”. At their core, lifecycle methods enable you to run code when events occur on an element. Even frameworks like React, which haved moved away from classes, still have similar concepts of doing actions when a component is changed in some way.&lt;/p&gt;

&lt;p&gt;Let’s take a look at some of the lifecycle methods that are baked into the browser’s implementation.&lt;/p&gt;

&lt;p&gt;Custom elements have 4 lifecycle methods that can be attached to a component.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Callback Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;connectedCallback&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ran when attached to the DOM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;disconnectedCallback&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ran when unattached to the DOM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;attributeChangedCallback&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ran when one of the web component’s attributes is changed. Must explicitly track&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;adoptedCallback&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ran when moved from one HTML document to another&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;While each of them has their uses, we’ll primarily be focusing on the first 3. &lt;code&gt;adoptedCallback&lt;/code&gt; is primarily useful in niche circumstances and is therefore difficult to make a straightforward demo of.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that we know what the lifecycle methods are, let’s see an example of them in action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection Lifecycles
&lt;/h3&gt;

&lt;p&gt;The first two lifecycle methods we’ll be talking about are typically used as a pair together: &lt;code&gt;connectedCallback&lt;/code&gt; and &lt;code&gt;disconnectedCallback&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;connectedCallback&lt;/code&gt; is ran when a component is mounted onto the DOM. This means that when you want the element to be shown, you can change your &lt;code&gt;innerHTML&lt;/code&gt;, add event listeners to elements, or do any other kind of code logic meant to setup your component.&lt;/p&gt;

&lt;p&gt;Meanwhile, &lt;code&gt;disconnectedCallback&lt;/code&gt; is run when the element is being removed from the DOM. This is often used to remove event listeners added during the &lt;code&gt;connectedCallback&lt;/code&gt;, or do other forms of cleanup required for the element.&lt;/p&gt;

&lt;p&gt;Here’s a simple web component that renders a header with the text “Hello world”.&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="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I am connecting&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;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;h1&amp;gt;Hello world&amp;lt;/h1&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;disconnectedCallback&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I am leaving&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="nf"&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-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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://app.coderpad.io/sandbox?question_id=181059s" rel="noopener noreferrer"&gt;Run this code sample in a playground&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Attribute Changed
&lt;/h3&gt;

&lt;p&gt;While there are other methods to pass data to an element (which we’ll touch on shortly), the undeniable simplicity of attributes is hard to deny. They’re widely utilized in HTML-spec tags, and most display custom elements should be able to utilize attributes to pass data from a parent trivially.&lt;/p&gt;

&lt;p&gt;While &lt;code&gt;attributeChangedCallback&lt;/code&gt; is the lifecycle method used to detect when an attribute’s value is changed, you must tell the component which attributes to track.&lt;/p&gt;

&lt;p&gt;For example, in this example we’re tracking the &lt;code&gt;message&lt;/code&gt; attribute. If the &lt;code&gt;message&lt;/code&gt; attribute value changes, it will run &lt;code&gt;this.render()&lt;/code&gt;. However, any other attribute’s value changing will not trigger &lt;code&gt;attributeChangedCallback&lt;/code&gt; because nothing else is marked to be tracked.&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="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&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="nf"&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;// Could also be:&lt;/span&gt;
  &lt;span class="c1"&gt;// static observedAttributes = ['message'];&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&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;message&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="nf"&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;render&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;message&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;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello world&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;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/h1&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="nf"&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-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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://app.coderpad.io/sandbox?question_id=181060" rel="noopener noreferrer"&gt;Run this code sample in a playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll notice that the “&lt;code&gt;attributeChangedCallback&lt;/code&gt;” receives the name of the attribute changed, it’s previous value, and it’s current value. This is useful for granular manual change detection optimizations.&lt;/p&gt;

&lt;p&gt;However, utilizing attributes to pass values to a component has its limitations. To explain these limitations, we must first start by talking about serializability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serializability
&lt;/h2&gt;

&lt;p&gt;Serialization is the process of turning a data structure or object into a format that can be stored and reconstructed later. A simple example of serialization is using JSON to encode data.&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;hello&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="na"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;// "[{\"hello\": 1}, {\"other\":2}]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because this JavaScript object is simple and only utilizes &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Primitive" rel="noopener noreferrer"&gt;primitive data types&lt;/a&gt;, it’s relatively trivial to turn into a string. This string can then be saved to a file, sent over HTTP to a server (and back), and be reconstructed when the data is needed again.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This simplicity of serialization to JSON is one reason why JSON is such a popular format for transferring data over REST endpoints.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Serializing Limitations
&lt;/h3&gt;

&lt;p&gt;While simple objects and arrays can be serialized relatively trivially, there are limitations. For example, take the following code:&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;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;method&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="nf"&gt;log&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="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;While this code’s behavior may seem simple to us reading it as developers, think about it from a machine’s perspective.&lt;/p&gt;

&lt;p&gt;If we wanted to send this object to a server from a client remotely with the method intact, how should we do that?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;window&lt;/code&gt;, while available in the browser, is not available in NodeJS, which the server may likely be written in. Should we attempt to serialize the &lt;code&gt;window&lt;/code&gt; object and pass it along with the method? What about methods on the &lt;code&gt;window&lt;/code&gt; object? Should we do the same with those methods?&lt;/p&gt;

&lt;p&gt;On the other end of the scale, while &lt;code&gt;console.log&lt;/code&gt; &lt;em&gt;**is*&lt;/em&gt;* implemented in both NodeJS and browsers alike, it’s implemented using native code in both runtimes. How would we even begin to serialize native methods, even if we wanted to? &lt;em&gt;Maybe&lt;/em&gt; we could pass machine code? Even ignoring the security concerns, how would we handle the differences in machine code between a user’s ARM device and a server’s x86_64 architecture?&lt;/p&gt;

&lt;p&gt;All of this becomes a problem before you even consider that your server may well not be running NodeJS. How would you even begin to represent the concept of &lt;code&gt;this&lt;/code&gt; in a language like Java? How would you handle the differences between a dynamically typed language like JavaScript and C++?&lt;/p&gt;

&lt;h4&gt;
  
  
  Let’s Stringify Some Functions
&lt;/h4&gt;

&lt;p&gt;Now knowing the problems with serializing functions, you may wonder what happens if you run &lt;code&gt;JSON.stringify()&lt;/code&gt; on &lt;code&gt;obj&lt;/code&gt;?&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;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;method&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="nf"&gt;log&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="nb"&gt;window&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;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&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;It simply omits the key from the JSON string. This is important to keep in mind as we go forward.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTML Attribute Strings
&lt;/h3&gt;

&lt;p&gt;Why are we talking about serialization in this article? To answer that, I want to mention two truths about HTML elements.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML attributes are case insensitive&lt;/li&gt;
&lt;li&gt;HTML attributes must be strings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first of these truths is simply that for any attribute, you can change the key casing and it will respond the same. According to HTML spec, there is no difference between:&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;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And:&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;input&lt;/span&gt; &lt;span class="na"&gt;tYpE=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second truth is much more relevant to us in this discussion. While it might seem like you can assign non-string values to an attribute, they’re always parsed as strings under-the-hood.&lt;/p&gt;

&lt;p&gt;You might think about being tricky and using JavaScript to assign non-string values to an attribute:&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;const&lt;/span&gt; &lt;span class="nx"&gt;el&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="nf"&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;input&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&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;data-arr&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, the attribute’s assigned value may not match your expectations:&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;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;data-arr=&lt;/span&gt;&lt;span class="s"&gt;"1,2,3,4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll notice the lack of brackets in the attribute. This is because JavaScript is implicitly running &lt;code&gt;toString&lt;/code&gt; on your array, which turns it into a string before assigning it to the attribute.&lt;/p&gt;

&lt;p&gt;No matter how you spin it - your attribute will be a string.&lt;/p&gt;

&lt;p&gt;This is also why when trying to use attributes for non-string values you may run into otherwise unexpected behavior. This is true even for built-in elements, such as &lt;code&gt;input&lt;/code&gt;.&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;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;checked=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without being aware of this HTML attribute limitation, you may well expect the checkbox to be unchecked. However, when rendered, it appears checked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?language=html&amp;amp;contents=%3Cinput%20type%3D%22checkbox%22%20checked%3D%22false%22%2F%3E" rel="noopener noreferrer"&gt;Run this code sample in a playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is because you’re not passing the boolean &lt;code&gt;false&lt;/code&gt;, you’re passing the string &lt;code&gt;"false"&lt;/code&gt;, which is (confusingly) truthy.&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some attributes are smart enough to know when you’re intending to assign a number or other primitive value to an element via an attribute, but the implementation internally might look something like:&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="nc"&gt;NumValidator&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&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="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&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;max&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="nf"&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&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;// Coerce "attribute.value" to a number. Again, attributes&lt;/span&gt;
      &lt;span class="c1"&gt;// can only be passed as a string&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&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;max&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&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;While this tends to be the extent of HTML element’s deserializing of attributes, we can extend this functionality much further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pass Array of Strings
&lt;/h2&gt;

&lt;p&gt;As we touched on shortly, if we simply try to pass an array to an attribute using JavaScript’s &lt;code&gt;setAttribute&lt;/code&gt;, it will not include the brackets. This is due to &lt;code&gt;Array.toString()&lt;/code&gt;’s output.&lt;/p&gt;

&lt;p&gt;If we attempted to pass the array &lt;code&gt;["test", "another", "hello"]&lt;/code&gt; from JS to an attribute, the output would look like this:&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&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="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&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;todos&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="nf"&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;render&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;todos&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;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&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;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todos&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&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="nf"&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-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;my-component&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"mycomp"&lt;/span&gt; &lt;span class="na"&gt;todos=&lt;/span&gt;&lt;span class="s"&gt;"test,another,hello"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/my-component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=181062" rel="noopener noreferrer"&gt;Run this code sample in a playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because of the output of &lt;code&gt;toString&lt;/code&gt;, it’s difficult to convert the attribute value back into a string. As such, we only display the data inside of a &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag. But lists don’t belong in a single paragraph tag! They belong in a &lt;code&gt;ul&lt;/code&gt; with individual &lt;code&gt;li&lt;/code&gt;s per item in the list. After all, &lt;a href="https://coderpad.io/blog/introduction-to-web-accessibility-a11y/" rel="noopener noreferrer"&gt;semantic HTML is integral for an accessible website&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Lets instead use &lt;code&gt;JSON.stringify&lt;/code&gt; to serialize this data, pass that string to the attribute value, then deserialize that in the element using &lt;code&gt;JSON.parse&lt;/code&gt;.&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&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="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&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;todos&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="nf"&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;render&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;todosArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&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;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[]&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todosArr&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;todoEls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todosArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/li&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&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;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;ul&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todoEls&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/ul&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="nf"&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-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;my-component&lt;/span&gt; &lt;span class="na"&gt;todos=&lt;/span&gt;&lt;span class="s"&gt;"[&amp;amp;quot;hello&amp;amp;quot;,&amp;amp;quot;this&amp;amp;quot;]"&lt;/span&gt;&lt;span class="nt"&gt;&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;&lt;a href="https://app.coderpad.io/sandbox?question_id=181063" rel="noopener noreferrer"&gt;Run this code sample in a playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using this method, we’re able to get an array in our &lt;code&gt;render&lt;/code&gt; method. From there, we simply &lt;code&gt;map&lt;/code&gt; over that array to create &lt;code&gt;li&lt;/code&gt; elements, then pass that to our &lt;code&gt;innerHTML&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pass Array of Objects
&lt;/h2&gt;

&lt;p&gt;While an array of strings is a straightforward demonstration of serializing attributes, it’s hardly representative of real-world data structures. &lt;/p&gt;

&lt;p&gt;Let’s start working towards making our data more realistic. A good start might be to turn our array of strings into an array of objects. After all, we want to be able to mark items “completed” in a todo app.&lt;/p&gt;

&lt;p&gt;For now, we’ll keep it small, and we’ll grow it later. Let’s keep track of the “name” of the todo item, and whether or not it’s been completed:&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;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;}];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s take a look at how we can display this in a reasonable manner using our custom element:&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&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="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&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;todos&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="nf"&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="nf"&gt;render&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;todosArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&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;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[]&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;todoEls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todosArr&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`
              &amp;lt;li&amp;gt;                 
                &amp;lt;!-- checked=”false” doesn’t do what you might think --&amp;gt;
                &amp;lt;input type="checkbox" &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&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="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;todo&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;
              &amp;lt;/li&amp;gt;
          `&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&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;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;ul&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;todoEls&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/ul&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="nf"&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-component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&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;my-component&lt;/span&gt;
  &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"mycomp"&lt;/span&gt;
  &lt;span class="na"&gt;todos=&lt;/span&gt;&lt;span class="s"&gt;"[{&amp;amp;quot;name&amp;amp;quot;:&amp;amp;quot;hello&amp;amp;quot;,&amp;amp;quot;completed&amp;amp;quot;:false}]"&lt;/span&gt;&lt;span class="nt"&gt;&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;blockquote&gt;
&lt;p&gt;Remember, checked=”false” will leave a checkbox checked. This is because “false” is a truthy string. Reference our “serializing limitations” sections for more reading.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that we’re displaying these checkboxes, let’s add a way to toggle them!&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;var&lt;/span&gt; &lt;span class="nx"&gt;todoList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;toggleAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;todoList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&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;todo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="nf"&gt;changeElement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;changeElement&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;compEl&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="nf"&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;#mycomp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;compEl&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;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoList&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;Now, all we need to do is run the function “toggleAll” on a button press and it will update the checkboxes in our custom element.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=181065" rel="noopener noreferrer"&gt;Run this code sample in a playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have a way to toggle all checkboxes, let’s look at how we can toggle individual todo items.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pass Objects with Functions
&lt;/h2&gt;

&lt;p&gt;While there are many ways to have user input in a custom element interact with a parent’s data set, let’s store a method in each todo object and pass it into the custom element.&lt;/p&gt;

&lt;p&gt;This pattern follows best practices for components by keeping the data passing unidirectional. In the past, we’ve touched on how to &lt;a href="https://coderpad.io/blog/master-react-unidirectional-data-flow/" rel="noopener noreferrer"&gt;keep your components unidirectional&lt;/a&gt; for React and Web Components alike.&lt;/p&gt;

&lt;p&gt;Let’s change a todo object to reflect something similar:&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="nx"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputEl&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="na"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;todoId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;:&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="nf"&gt;toggleTodoItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoId&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;Then, we’ll simply implement our &lt;code&gt;toggleTodoItem&lt;/code&gt; method using the ID to modify the related todo object:&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;function&lt;/span&gt; &lt;span class="nf"&gt;toggleTodoItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;thisTodo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todoList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nx"&gt;todoId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;thisTodo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;thisTodo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;changeElement&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;changeElement&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;compEl&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="nf"&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;#mycomp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;compEl&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;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoList&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;With these changes, we have all of the logic we need from our parent to handle the checkbox logic. Now we need to update our custom element to trigger the &lt;code&gt;onChange&lt;/code&gt; method when the checkbox is checked. In order to bind an event listener the “input” element, we need to access the underlying &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement" rel="noopener noreferrer"&gt;HTMLElement&lt;/a&gt; reference. To do this, we’ll need to migrate away from the &lt;code&gt;innerHTML&lt;/code&gt; logic we were using previously in favor of &lt;code&gt;document.createElement&lt;/code&gt;.&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="nf"&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="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Create list element&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;todosArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&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;todos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[]&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;todoEls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todosArr&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&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;// Use `createElement` to get access to the element. We can then add event listeners&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkboxEl&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="nf"&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;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;checkboxEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;checkbox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

          &lt;span class="c1"&gt;// This doesn't work, we'll explain why shortly&lt;/span&gt;
          &lt;span class="nx"&gt;checkboxEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="nx"&gt;checkboxEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&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;liEl&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="nf"&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;li&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;liEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;checkboxEl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;liEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;liEl&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;ulEl&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="nf"&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;ul&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for &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;liEl&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;todoEls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ulEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;liEl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Add header. This should update to tell us how many items are completed&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;header&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="nf"&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;h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todosArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Reconstruct logic&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&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="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ulEl&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;Awesome! Now we’ve made all of the changes required, let’s see if it all works together!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=181066" rel="noopener noreferrer"&gt;Run this code sample in a playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh… Weird… While our checkboxes seem to be updating, our &lt;code&gt;h1&lt;/code&gt; is not. What’s more, if we look in our developer console, we don’t see the &lt;code&gt;console.log&lt;/code&gt;s we would expect to see during a re-render.&lt;/p&gt;

&lt;p&gt;Why is that?&lt;/p&gt;

&lt;p&gt;Well, as we mentioned in our section about serialization limitations, functions are not serializable. Because of this, when an object with methods are passed to &lt;code&gt;JSON.parse&lt;/code&gt;, those keys are removed. When we’re adding our event listener, the function is &lt;code&gt;undefined&lt;/code&gt;, and therefore doesn’t do anything.&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="nx"&gt;checkboxEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// onChange is undefined&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The checkbox’s state visually updating without being reflected in our data is an example of a misalignment between the DOM and the data we used to build the DOM.&lt;/p&gt;

&lt;p&gt;However, we can verify that our code is correct outside of serialization issues. If we change that line of code to utilize the global function &lt;code&gt;toggleTodoItem&lt;/code&gt; directly, it functions as expected:&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="nx"&gt;checkboxEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&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;change&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;toggleTodoItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Update this line of code in the sandbox above to see the correct behavior!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While this works for our current setup, one of the advantages of building custom elements is the ability to split out your application to multiple files in order to keep your app’s codebase organized. As soon as &lt;code&gt;toggleTodoItem&lt;/code&gt; is no longer in the same scope as the custom element, this code will break.&lt;/p&gt;

&lt;p&gt;If this isn’t a good long-term solution, what can we do to fix our issue with serialization?&lt;/p&gt;

&lt;h2&gt;
  
  
  Pass via Props, not Attributes
&lt;/h2&gt;

&lt;p&gt;Attributes provide a simple method of passing primitive data to your custom elements. However, as we’ve demonstrated, it falls flat in more complex usage due to the requirement to serialize your data. &lt;/p&gt;

&lt;p&gt;Knowing that we’re unable to bypass this limitation using attributes, let’s instead take advantage of JavaScript classes to pass data more directly.&lt;/p&gt;

&lt;p&gt;Because our components are classes that extend &lt;code&gt;HTMLElement&lt;/code&gt;, we’re able to access our properties and methods from our custom element’s parent. Let’s say we want to update &lt;code&gt;todos&lt;/code&gt; and render once the property is changed.&lt;/p&gt;

&lt;p&gt;To do this, we’ll simply add a method to our component’s class called “&lt;code&gt;setTodos&lt;/code&gt;”. This method will then be accessible when we query for our element using &lt;code&gt;document.querySelector&lt;/code&gt;.&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="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;HTMLElement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="nf"&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="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todos&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;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;todos&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="nf"&gt;clear&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="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&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;// ...&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;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;changeElement&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;compEl&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="nf"&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;#mycomp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;compEl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTodos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;todoList&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://app.coderpad.io/sandbox?question_id=181067" rel="noopener noreferrer"&gt;Run this code sample in a playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, if we toggle items in our todo list, our &lt;code&gt;h1&lt;/code&gt; tag updates as we would expect: we’ve solved the mismatch between our DOM and our data layer!&lt;/p&gt;

&lt;p&gt;Because we’re updating the &lt;em&gt;properties&lt;/em&gt; of our custom elements, we call this “passing via properties”, which solves the serialization issues of “passing via attributes”.&lt;/p&gt;

&lt;p&gt;But that’s not all! Properties have a hidden advantage over attributes for data passing as well: memory size.&lt;/p&gt;

&lt;p&gt;When we were serializing our todos into attributes, we were duplicating our data. Not only were we keeping the todo list in-memory within our JavaScript, but the browser keeps loaded DOM elements in memory as well. This means that for every todo we added, not only were we keeping a copy in JavaScript, but in the DOM as well (via attribute string).&lt;/p&gt;

&lt;p&gt;But surely, that’s the only way memory is improved when migrating to properties, right? Wrong!&lt;/p&gt;

&lt;p&gt;Because keep in mind, on top of being loaded in-memory in JS in our main &lt;code&gt;script&lt;/code&gt; tag, and in the browser via the DOM, we were also deserializing it in our custom element as well! This meant that we were keeping a &lt;em&gt;third&lt;/em&gt; copy of our data initialized in-memory simultaneously!&lt;/p&gt;

&lt;p&gt;While these performance considerations might not matter in a demo application, they would add significant complications in production-scale apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We’ve covered a lot today! We’ve introduced some of the core concepts at play with web components, how we’re able to best implement various functionality, and the limitations of the DOM.&lt;/p&gt;

&lt;p&gt;While we spoke a lot about passing data by attributes vs. properties today, there are pros and cons to both. Ideally, we would want the best of both worlds: the ability to pass data via property in order to avoid serialization, but keep the simplicity of attributes by reflecting their value alongside the related DOM element.&lt;/p&gt;

&lt;p&gt;Something else we’ve lost since the start of this article is code readability in element creation. Originally, when we were using &lt;code&gt;innerHTML&lt;/code&gt;, we were able to see a visual representation of the output DOM. When we needed to add event listeners, however, we were required to switch to &lt;code&gt;document.createElement&lt;/code&gt;. Preferably, we could attach event listeners without sacrificing the in-code HTML representation of our custom element’s rendered output.&lt;/p&gt;

&lt;p&gt;While these features may not be baked into the web component specifications themselves, there are other options available. In our next article, we’ll take a look at a lightweight framework we can utilize to build better web components that can integrate with many other frontend stacks!&lt;/p&gt;

</description>
      <category>webcomponents</category>
      <category>javascript</category>
      <category>vanillajs</category>
      <category>programming</category>
    </item>
    <item>
      <title>GitHub Copilot Breaks Bad Interviews</title>
      <dc:creator>CoderPad Team</dc:creator>
      <pubDate>Tue, 22 Mar 2022 12:37:42 +0000</pubDate>
      <link>https://forem.com/coderpad/github-copilot-breaks-bad-interviews-4pkg</link>
      <guid>https://forem.com/coderpad/github-copilot-breaks-bad-interviews-4pkg</guid>
      <description>&lt;p&gt;&lt;a href="https://copilot.github.com/"&gt;GitHub Copilot&lt;/a&gt; was recently announced! In the past few years, we’ve seen artificial intelligence (AI) revolutionize aspects of technology such as image recognition, recommendation algorithms, and more. With Copilot, GitHub is hoping to add “code generation” to that list of items. In this article, we’ll explain what GitHub Copilot is, why some people are concerned with allowing its usage in technical interviews, and how to build your interviews to be better in general and therefore more resilient to auto-generated code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is GitHub Copilot?
&lt;/h2&gt;

&lt;p&gt;GitHub Copilot is a VSCode extension that’s able to autocomplete code snippets. While we've had some form of code completion for some time now, they've been relatively limited in one way or another. Usually, they tend to rely on existing code in your files or can only suggest a tiny amount of code per suggestion. Other times, code completion can be no more than a predefined snippet of code without considering any additional context.&lt;/p&gt;

&lt;p&gt;Copilot offers the ability to suggest multi-line and contextually aware code suggestions - powered by AI. GitHub says this tool is available for most programming languages and can implement entire functions off of their names alone.&lt;/p&gt;

&lt;p&gt;They’re not alone in this endeavor, however. GitHub is working in collaboration with OpenAI, the company behind the extremely powerful GPT-3 AI tool. Between the training dataset consisting of GitHub’s public source code and OpenAI’s expertise in AI generation, it has the potential to provide impressive results.&lt;/p&gt;

&lt;p&gt;Taking an example from their website, it’s able to generate an implementation of a date utility from nothing more than the function name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nM5-jaLw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://coderpad.io/wp-content/uploads/2021/07/image-1-1024x344.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nM5-jaLw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://coderpad.io/wp-content/uploads/2021/07/image-1-1024x344.png" alt="img" width="880" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s incredible that given the simple input of:&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;function&lt;/span&gt; &lt;span class="nx"&gt;calculateDaysBetweenDates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;date2&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;It’s able to generate the following code which functions how you might expect:&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;function&lt;/span&gt; &lt;span class="nx"&gt;calculateDaysBetweenDates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;date2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;oneDay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;date1InMillis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;date2InMillis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;date2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;days&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;date2InMillis&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;date1InMillis&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;oneDay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;days&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;While every new tech has its naysayers, and even some on our team are skeptical of its true utility, it’s undoubtedly a powerful tool that will, for some, change the way they write code. &lt;/p&gt;

&lt;p&gt;GitHub’s not alone in this venture of AI-powered code generation, either! Other companies, such as &lt;a href="https://www.kite.com/"&gt;Kite&lt;/a&gt; or &lt;a href="https://www.tabnine.com/"&gt;TabNine&lt;/a&gt; are working hard at this problem space as well! Whether we want it to or not, AI-generated code helpers are here to stay.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does Copilot Threaten Tech Interviews?
&lt;/h2&gt;

&lt;p&gt;In the current tech interview landscape, algorithms reign as the leading method of technical assessment. While we’ve touched on &lt;a href="https://coderpad.io/blog/5-tips-for-tech-recruiting/"&gt;why this shouldn’t be the case&lt;/a&gt; before, Copilot in particular breaks algorithm questions in significant ways by being able to rapidly generate solutions to algorithmic problems.&lt;/p&gt;

&lt;p&gt;Let’s see how Copilot interacts with some common interview questions.&lt;/p&gt;

&lt;p&gt;One common question that’s a favorite of interviewers hoping to quickly glean mathematical competency is a function to check if a given number is prime or not.&lt;/p&gt;

&lt;p&gt;Well, it’s been a few years since I’ve refreshed my math skills, so they might be a little shakey. I should be able to figure it out all the same. &lt;/p&gt;

&lt;p&gt;Let’s open VSCode and start implementing the function.&lt;/p&gt;



&lt;p&gt;Wow! I hadn’t even had a chance to add the parameters to the “isPrime” function before Copilot had already made a suggestion!&lt;/p&gt;

&lt;p&gt;Looking through the suggested code, it seems clean and functions as expected!&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;function&lt;/span&gt; &lt;span class="nx"&gt;isPrime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&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="kc"&gt;true&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;Sure, we could change the &lt;code&gt;var&lt;/code&gt; to a &lt;code&gt;const&lt;/code&gt;, but this is code that I wouldn’t blink twice at in a code review!&lt;/p&gt;

&lt;p&gt;While this may seem like an outlier, Copilot seems to excel in these algorithm-based questions. &lt;/p&gt;

&lt;p&gt;But surely &lt;code&gt;isPrime&lt;/code&gt; would be too trivial for a &lt;em&gt;real&lt;/em&gt; interview question, right? Perhaps, but watch what happens when a popular coding YouTuber attempts to utilize Copilot to solve Leetcode interview questions&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=FHwnrYm0mNc"&gt;https://www.youtube.com/watch?v=FHwnrYm0mNc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without fail, Copilot is able to generate usable code for each difficulty level of algorithms given to it. Further, the solutions are all more performant than the average of submissions. For the permutation question, it’s able to be faster than 88% of other submissions!&lt;/p&gt;

&lt;p&gt;“Given how predominant these types of interview questions are, we could be in big trouble if some candidates are less-than-forthcoming with their usage of Copilot in coding exercises.”&lt;/p&gt;

&lt;p&gt;While this may be true for some interviews, if your interviews are susceptible to collapse with Copilot in the picture, you’re already facing this problem whether you’re aware of it or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Algorithms Are Breaking Your Interviews
&lt;/h2&gt;

&lt;p&gt;On paper, algorithm based interview questions sound like a great way to assess a candidate's skills. They can help give guidance on a candidate's understanding of logic complexity, how efficient (or inefficient) a specific solution is, and is usually an insight into a candidate’s ability to think in abstract manners. &lt;/p&gt;

&lt;p&gt;However, in practice algorithm questions tend to go against the grain of real-world engineering. Ideally, an interview process should act as a way to evaluate a candidate’s ability to do the same kind of engineering they’d be using in their projects at your company. While a developer may, with resources, implement an algorithm once in a while, they’re more than likely doing things like refactoring significantly more often.&lt;/p&gt;

&lt;p&gt;We’ve written more about how &lt;a href="https://coderpad.io/blog/5-tips-for-tech-recruiting/#less-algorithms-more-demos"&gt;algorithms aren’t often effective as interview questions in the past.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But more than being unrepresentative of the job, algorithm questions are often easy to cheat - without the use of GitHub Copilot. Because most algorithm questions are significantly similar to each other, there’s often a small selection of tips and tricks a candidate can memorize in order to drastically improve their output in these styles of interviews.&lt;/p&gt;

&lt;p&gt;There’s even the potential for a candidate to be able to output an algorithm verbatim. There are hundreds of sites that will give a candidate one algorithm question after another in the hopes of improving their understanding of these algorithms.&lt;/p&gt;

&lt;p&gt;But with GitHub Copilot, the propensity for cheating on an algorithm question rises significantly. As we’ve demonstrated previously in the article, it’s capable of generating significant portions of code at a time. In fact, Copilot is so proficient at algorithm questions that a &lt;a href="https://github.com/CoderPad/github-copilot-interview-question"&gt;non-trivial number of algorithm questions we asked it to solve were done&lt;/a&gt; before we could even finish the function signature. All it takes is a candidate to give Copilot the name of the function and paste the results into their assessment editor.&lt;/p&gt;

&lt;p&gt;Further, folks wanting to cheat have had the ability to do something similar for some time now in the form of forum questions. Simply lookup any algorithm on a code forum or site like &lt;a href="http://stackoverflow.com/"&gt;StackOverflow&lt;/a&gt; and you can find hundreds of answers at your disposal. &lt;/p&gt;

&lt;p&gt;In fact, many have pointed out that Copilot’s process of looking up code based on its expected constraints is similar to one that a developer might experience by searching StackOverflow for code snippets. Funnily, some thought the idea so similar they decided to build an alternative VSCode plugin to Copilot that simply &lt;a href="https://github.com/hieunc229/copilot-clone"&gt;looks up StackOverflow answers as suggestions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Regardless of how the question is answered, a candidate’s skill at these types of questions might not reflect their capabilities in other aspects of the codebase. That’s why, in order to access candidates properly, it might be the right move to move away from these questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Fix Your Interviews
&lt;/h2&gt;

&lt;p&gt;While you &lt;em&gt;could&lt;/em&gt; simply require candidates to use a non-VSCode IDE for your technical assessments, there are no guarantees that your take-home projects will be spared the same fate. Further, while VSCode is the launch platform for Copilot, it’s more than likely to gain plugins for other IDEs in the future as well.&lt;/p&gt;

&lt;p&gt;But what of it? Let’s say your company doesn’t do take-home projects (&lt;a href="https://coderpad.io/blog/hire-better-faster-and-in-a-more-human-way-with-take-homes/"&gt;even though you totally should&lt;/a&gt;), what of it? Well, even if restricting VSCode would work to avoid Copilot for a while, you ideally want to be able to standardize your IDE platform for all candidates. &lt;/p&gt;

&lt;p&gt;Plus, as we touched on in the previous section, algorithm-based interview questions are still able to be manipulated - with or without Copilot.&lt;/p&gt;

&lt;p&gt;The solution to fixing your interviews should be two-fold:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;More representative questions of the job

&lt;ul&gt;
&lt;li&gt;Require more thought process than memorization&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Better communication with candidates&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the first, make sure your questions are examples of real-world challenges you’ve seen in your project’s codebase. Some great examples of this might be “setting up a backend endpoint &lt;a href="https://coderpad.io/resources/docs/full-stack-databases/"&gt;connected to your database&lt;/a&gt;” or “&lt;a href="https://coderpad.io/blog/master-react-unidirectional-data-flow/#challenge"&gt;refactor this React component to be unidirectional&lt;/a&gt;”.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you’re using CoderPad, we have a &lt;a href="https://coderpad.io/resources/docs/question-bank/example-questions/"&gt;great selection of questions available in our Question Bank that you can personalize to fix the unique needs of your team&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second point might sound obvious, but look at it this way: Engineering often utilizes more “soft” skills than we usually credit. In any engineering team you’ll need to do code review, create technical documentation, and communicate with others on your team. Being able to program is well and good, but without soft skills your ability to leverage those skills goes flat.&lt;/p&gt;

&lt;p&gt;Even if a candidate does end up using Copilot to generate a non-trivial portion of a candidates’ submitted code, you should be able to ask them what their review process of the generated code looked like. Does it follow their code standards? What alternatives did it suggest and why did they choose that one? How maintainable is said code? Are there edge-cases not yet covered?&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;GitHub Copilot is a remarkable piece of technology. It will be interesting to watch as it continues to develop and see how developers will utilize it in their day-to-day. As it becomes more and more relevant, we need to make sure our interviews are structured to handle(and prevent) its capabilities.&lt;/p&gt;

&lt;p&gt;In fact, we’ve created &lt;a href="https://github.com/CoderPad/github-copilot-interview-question"&gt;a GitHub repo to showcase a wide range of interview questions that Copilot has been able to successfully generate&lt;/a&gt;, given little input.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/CoderPad/github-copilot-interview-question"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eyXgHG_o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://coderpad.io/wp-content/uploads/2021/07/image-1024x828.png" alt="The GitHub Copilot interview questions GitHub repo" width="880" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to open a PR if you find a question that you think should be present. If you’re worried about your interview question being susceptible to Copilot, maybe drop by the repo and see if it’s in the list.&lt;/p&gt;

</description>
      <category>interviewing</category>
      <category>recruiting</category>
      <category>githubcopilot</category>
      <category>github</category>
    </item>
    <item>
      <title>Introduction to Web Accessibility (A11Y)</title>
      <dc:creator>CoderPad Team</dc:creator>
      <pubDate>Fri, 18 Mar 2022 17:24:09 +0000</pubDate>
      <link>https://forem.com/coderpad/introduction-to-web-accessibility-a11y-2e7i</link>
      <guid>https://forem.com/coderpad/introduction-to-web-accessibility-a11y-2e7i</guid>
      <description>&lt;p&gt;If you’ve come across this article but haven't heard about web accessibility (often shortened to "A11Y") before, that's okay. We're all learning at different speeds and come across new things all the time. That said, accessibility is a critical component of any frontend engineer's responsibilities. We implore you to explore what that means, not just in this blog post but beyond with your teams and communities.&lt;/p&gt;

&lt;p&gt;First, let's define what "accessibility" is. Accessibility in engineering is &lt;a href="https://dl.acm.org/doi/10.1145/2596695.2596719" rel="noopener noreferrer"&gt;"the process of creating products that are usable by people with the widest possible range of abilities."&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One example of accessibility is the needs of blind or low-vision users. They may rely on &lt;a href="https://www.afb.org/blindness-and-low-vision/using-technology/assistive-technology-products/screen-readers" rel="noopener noreferrer"&gt;screen readers&lt;/a&gt; or other assistive technologies, which allows them to navigate their computer with their other senses. These methods may be used in tandem with the visual experience for some or used independently to navigate their computer auditorily or tactilely.&lt;/p&gt;

&lt;p&gt;Another example is users with limited mobility who utilize specialty hardware, such as buttons, to trigger different behaviors on their machine.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;If you're a visual learner who would like to see some short-and-quick workflows from users like this, &lt;a href="https://www.youtube.com/watch?v=XB4cjbYywqg" rel="noopener noreferrer"&gt;one of Apple's ads&lt;/a&gt; displays a few use cases that proper accessibility support can enable.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Something to keep in mind is that these disabilities may not be permanent. For instance, if you fall and break your arm, you may be only using one arm while healing. Likewise, there are situational impairments as well. If you're holding a cup of coffee in one hand, you'll only be using the other for device usage. Here's a chart that outlines a few more of these examples:​&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Permanent&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Temporary&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Situational&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th&gt;Touch&lt;/th&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fone_arm.png" alt=""&gt;&lt;br&gt;One arm&lt;/td&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Farm_injury.png" alt=""&gt;&lt;br&gt;Arm injury&lt;/td&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fnew_parent.png" alt=""&gt;&lt;br&gt;New parent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;See&lt;/th&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fblind.png" alt=""&gt;&lt;br&gt;Blind&lt;/td&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fcataract.png" alt=""&gt;&lt;br&gt;Cataract&lt;/td&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fdistracted_driver.png" alt=""&gt;&lt;br&gt;Distracted driver&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;Hear&lt;/th&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fdeaf.png" alt=""&gt;&lt;br&gt;Deaf&lt;/td&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fear_infection.png" alt=""&gt;&lt;br&gt;Ear infection&lt;/td&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fbartender.png" alt=""&gt;&lt;br&gt;Bartender&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;th&gt;Speak&lt;/th&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fnon_verbal.png" alt=""&gt;&lt;br&gt;Non-verbal&lt;/td&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Flaryngitis.png" alt=""&gt;&lt;br&gt;Laryngitis&lt;/td&gt;
&lt;td&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fheavy_accent.png" alt=""&gt;&lt;br&gt;Heavy accent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;​&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Microsoft originally created this chart as part of their &lt;a href="https://download.microsoft.com/download/b/0/d/b0d4bf87-09ce-4417-8f28-d60703d672ed/inclusive_toolkit_manual_final.pdf" rel="noopener noreferrer"&gt;Inclusive Toolkit&lt;/a&gt; manual&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Creating an application that's accessible means that you're making a better experience for &lt;em&gt;all&lt;/em&gt; of your users.&lt;/p&gt;

&lt;p&gt;In addition to both moral and financial incentives (by opening the door to more users), many organizations have a legal requirement to meet accessibility. U.S. government software is subject to &lt;a href="https://www.section508.gov/manage/laws-and-policies" rel="noopener noreferrer"&gt;Section 508&lt;/a&gt;, which requires compliance to the Web Content Accessibility Guidelines (also known as WCAG, which we'll touch on later). Likewise, private US companies may be subject to compliance due to the "Americans with Disabilities Act" (shortened to "ADA"). The U.S. isn't the only country with these requirements, either. According to&lt;a href="https://www.w3.org/WAI/policies/" rel="noopener noreferrer"&gt; WCAG's reference page for various legal laws&lt;/a&gt;, there are at least 40 such laws in place around the world.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Please note that we are &lt;em&gt;not&lt;/em&gt; giving legal advice. This article is simply meant for educational purposes for individuals. Consult legal authorities for the appropriate jurisdiction&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Accessibility isn't a pure science, however. If you aren’t a user of assistive technology, this may be an abstract idea at first. However, think of it like this: the colors an app uses or a button's visual placement may convey different messages and meanings depending on their context. This same problem applies to users of screen-readers and other accessible tech as well, just with different constraints. If the screen is visually cluttered, the content may be more difficult to read. Likewise, different accessibility methods will lead to different experiences for users of assistive technology. In both of these scenarios, there may not be objectively correct answers - some may prefer a button placed visually to the left, while others might advocate for it on the right. Similarly, how something is read using a screen reader may make sense to some, but might be confusingly expressed to others.&lt;/p&gt;

&lt;h1 id="wcag"&gt;Sensible Standards&lt;/h1&gt;

&lt;p&gt;While accessibility has some levels of subjectivity, it's important to note that there &lt;em&gt;are&lt;/em&gt; standards surrounding web application's accessibility support. &lt;a href="https://www.w3.org/WAI/" rel="noopener noreferrer"&gt;"Web Content Accessibility Guidelines"&lt;/a&gt; (shortened to "WCAG") are guidelines to follow when considering your app's accessibility. These guidelines are published by a subgroup of the &lt;a href="https://www.w3.org/" rel="noopener noreferrer"&gt;World Wide Web Consortium&lt;/a&gt; (shortened to "W3C"), the main international standards organization for the Internet. WCAG acts as the de-facto standard for accessibility guidelines.&lt;/p&gt;

&lt;p&gt;There are different scales of accessibility as well. &lt;a href="https://www.w3.org/WAI/WCAG2AA-Conformance" rel="noopener noreferrer"&gt;WCAG includes three different levels of conformance&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Level A is the minimum level.&lt;/li&gt;
&lt;li&gt;Level AA includes all Level A and AA requirements. Many organizations strive to meet Level AA.&lt;/li&gt;
&lt;li&gt;Level AAA includes all Level A, AA, and AAA requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meeting AA requirements is typically seen as a good commitment to accessibility, but AAA will open more doors to your users and is the gold standard for accessible user experience.&lt;/p&gt;

&lt;p&gt;Far from a comprehensive list, A requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/WCAG21/#non-text-content" rel="noopener noreferrer"&gt;Non-text content to have alternative text&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/WCAG21/#pause-stop-hide" rel="noopener noreferrer"&gt;Automatically moving elements (such as GIFs) must be able to be paused&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meanwhile, AA covers things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Screen reader experience&lt;/li&gt;
&lt;li&gt;Minimum contrast guidelines&lt;/li&gt;
&lt;li&gt;Text resize support&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/WCAG21/#captions-live" rel="noopener noreferrer"&gt;Video captions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Basic support for keyboard navigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, AAA includes support for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/WCAG21/#contrast-enhanced" rel="noopener noreferrer"&gt;Enhanced contrast&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/WCAG21/#animation-from-interactions" rel="noopener noreferrer"&gt;Reduced/restricted animations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/WCAG21/#sign-language-prerecorded" rel="noopener noreferrer"&gt;Video sign language support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Full website functionality with keyboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interested in reading the full list? &lt;a href="https://www.w3.org/WAI/WCAG21/quickref/" rel="noopener noreferrer"&gt;Read the quick reference to WCAG 2.1&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id="html-semantic-tags"&gt;Smartly using Semantic HTML Tags&lt;/h1&gt;

&lt;p&gt;One of the easiest things you can do for your application's accessibility is to use semantic HTML tags.&lt;/p&gt;

&lt;p&gt;Let's say we have HTML to display fruits in a list:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!-- Inaccessible --&amp;gt;
&amp;lt;div&amp;gt;
    &amp;lt;div&amp;gt;Orange&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;Banana&amp;lt;/div&amp;gt;
    &amp;lt;div&amp;gt;Grapefruit&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;While this will display the contents, and you may be able to use CSS to add styling to make this look like a list, the browser has no way of knowing that this is a list. This is reflected in how screen readers read that HTML output.​​&lt;/p&gt;

&lt;p&gt;Voiceover reading of the content above&lt;/p&gt;

&lt;p&gt;Likewise, search engine crawlers won't know that this is a list. If you're only using &lt;code&gt;div&lt;/code&gt; tags as far as Google's concerned, you have no lists, no headings, nothing. This makes the page significantly less engaging and therefore rank more poorly.&lt;/p&gt;

&lt;p&gt;Let's compare that to using the correct HTML tags for a list.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!-- Accessible --&amp;gt;
&amp;lt;ul aria-label="Fruits"&amp;gt;
    &amp;lt;li&amp;gt;Orange&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Banana&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;Grapefruit&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Voiceover reading of the content above&lt;/p&gt;

&lt;p&gt;As you may be able to hear, this screen reader is now able to read out that it's a list and its name. It makes navigation of that list easier for those users by allowing them to quickly skip to the next list item and hear the index of an item in the list.&lt;/p&gt;

&lt;p&gt;Not only does this enhance the experience of assistive technology users browsing your list, but because search engine crawlers rely on HTML tags to inform what's what, your site may rank better in search engine queries as well! This is a massive boon to your site's SEO score.&lt;/p&gt;

&lt;h1 id="aria"&gt;Understand &lt;code&gt;aria-&lt;/code&gt; properties&lt;/h1&gt;

&lt;p&gt;In our previous example, we used an HTML attribute &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-label_attribute" rel="noopener noreferrer"&gt;&lt;code&gt;aria-label&lt;/code&gt;&lt;/a&gt; on our &lt;code&gt;ul&lt;/code&gt;. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA" rel="noopener noreferrer"&gt;ARIA is collection of HTML attributes that allow you to enhance the accessibility in applications&lt;/a&gt;. That said, &lt;em&gt;&lt;strong&gt;it is highly encouraged to use the suggested HTML tags instead of &lt;code&gt;aria&lt;/code&gt; attributes whenever possible&lt;/strong&gt;&lt;/em&gt;. Think of &lt;code&gt;aria&lt;/code&gt; as a complex low level API that can enhance your experience when done properly, but drastically harm user experience when improperly utilized.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;No ARIA is better than Bad ARIA &lt;a href="https://www.w3.org/TR/wai-aria-practices-1.1/#no_aria_better_bad_aria" rel="noopener noreferrer"&gt;WCAG WAI-ARIA Authoring Practices&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;A super small small subsection of &lt;code&gt;aria-&lt;/code&gt; attributes includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-labelledby_attribute" rel="noopener noreferrer"&gt;&lt;code&gt;aria-labelledby&lt;/code&gt;&lt;/a&gt; — Associate the element with another element's text as the label&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aria-expanded&lt;/code&gt; — A Boolean value meant to communicate when a dropdown is expanded&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aria-valuemin&lt;/code&gt; — The minimum allowed value in a numerical input&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aria-valuemax&lt;/code&gt; — The maximum allowed value of a numerical input&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additional to &lt;code&gt;aria&lt;/code&gt; props, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques#roles" rel="noopener noreferrer"&gt;the &lt;code&gt;role&lt;/code&gt; property&lt;/a&gt; allows to tell the browser what an element's intended purpose is, thus changing it's behavior with accessible tech. Again, this is a highly advanced (and often incorrectly deployed) API for complex apps. To learn more, &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/WAI-ARIA_basics" rel="noopener noreferrer"&gt;read through Mozilla's ARIA basics article.&lt;/a&gt;&lt;/p&gt;

&lt;h1 id="css"&gt;Classy CSS&lt;/h1&gt;

&lt;p&gt;While HTML relays a significant amount of information to assistive technologies like screen readers, it's not the only thing used to inform those tools. Certain CSS rules can change the functionality as well. After all, screen readers (and other tools) don't look through the source code of a website. Instead, they're looking at &lt;a href="https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/the-accessibility-tree" rel="noopener noreferrer"&gt;the accessibility tree&lt;/a&gt;: a modified version of the DOM. The accessibility tree and the DOM are both constructed by the browser from the website's source code.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Want to learn more about the DOM, how the browser constructs it, and what it's used for internally? &lt;a href="https://unicorn-utterances.com/posts/understanding-the-dom/" rel="noopener noreferrer"&gt;This article helps explain this in detail&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Because the DOM is influenced by CSS, it impacts the accessibility tree as well. For example, &lt;code&gt;display: none&lt;/code&gt; removes the element from the &lt;a href="https://benmyers.dev/blog/accessibility-tree/" rel="noopener noreferrer"&gt;accessibility tree&lt;/a&gt; and from the browsers visual output. This means that screen readers won't read the contents of an element with that rule applied. However, &lt;code&gt;visibility: hidden&lt;/code&gt; or &lt;code&gt;width: 0px&lt;/code&gt; will hide an element visually, but will still be read by screen readers.&lt;/p&gt;

&lt;p&gt;For this reason, there's a frequently used CSS class used to hide elements visually but not from screen readers:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are many ways which CSS can influence assistive technologies. &lt;a href="https://benmyers.dev/blog/css-can-influence-screenreaders/" rel="noopener noreferrer"&gt;Ben Myers covers this more in his blog post&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id="contrast"&gt;Contrast is Cool&lt;/h1&gt;

&lt;p&gt;While screen readers are imperative to frontend accessibility testing, a site's visuals can help provide a good experience for many users. While a certain color palette may be aesthetically pleasing, it may be difficult to read for a colorblind user. Colorblind users aren't the only ones impacted, however.&lt;/p&gt;

&lt;p&gt;While there are various reasons a user might not be able to see weakly contrasted color, everyone is different. See if you can distinguish the text from the background in the displayed image with poor contrast:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fcolor_fail-1024x340.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fcolor_fail-1024x340.png" alt="Dark gray text on a black background, failing AA accessibility guidelines"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, compare that to highly contrasting colors:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fcolor_pass-1024x350.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fcolor_pass-1024x350.png" alt="White text on a black background, passing AAA accessibility guidelines"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The contents are not only easier to distinguish from the background, but it's made easier to focus on as a result of the increased contrast.&lt;/p&gt;

&lt;p&gt;This said, not all contrasts are the same. Per WCAG guidelines, you may have a different ratio of contrast for different compliance levels. These contrast ratios depend on both font size as well as compliance level.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fpass_aa_large-1024x351.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fpass_aa_large-1024x351.png" alt="Light grey text passing AA for large text, but not small text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example you can see that the text passes the WCAG AA requirements for large text, but fails the same requirements for small text.&lt;/p&gt;

&lt;h1 id="font-resize"&gt;Fantastic Fonts&lt;/h1&gt;

&lt;p&gt;One of the most widely used accessibility features is font scaling. While many browsers default to a font size of &lt;code&gt;16px&lt;/code&gt;, the user is actually able to change settings on their device to configure websites to use a larger font size.&lt;/p&gt;

&lt;p&gt;Many phones using iOS and Android allow users to change the font size on their mobile devices. This feature is so commonplace that it often prompts users to change this setting when the phone is being set up.​&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fios_text_size-1024x707.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fios_text_size-1024x707.png" alt=""&gt;&lt;/a&gt;iOS font size settings screen&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fandroid_text_size-1024x732.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fandroid_text_size-1024x732.png" alt=""&gt;&lt;/a&gt;Android font size settings screen&lt;/p&gt;

&lt;p&gt;​&lt;/p&gt;

&lt;p&gt;Not only do you have these settings on mobile devices, but they're available on desktop as well.&lt;/p&gt;

&lt;p&gt;Using Chrome, go to &lt;a&gt;your settings page&lt;/a&gt;, and you should be able to set your font size.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fchrome_font_size-1024x219.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fchrome_font_size-1024x219.png" alt="Font settings in Chrome"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can do the same in Firefox in &lt;a&gt;your preferences&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Ffirefox_font_size-1024x258.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Ffirefox_font_size-1024x258.png" alt="Font settings in Firefox"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id="font-rem"&gt;Implementation&lt;/h2&gt;

&lt;p&gt;While browsers have the ability to set the font size, if you're using &lt;code&gt;px&lt;/code&gt;, &lt;code&gt;vw&lt;/code&gt;, &lt;code&gt;vh&lt;/code&gt;, or other unit values for your fonts, the browser will not update these font sizes for you. In order to have your application rescale the font size to match the browser settings, you'll need to use the &lt;code&gt;rem&lt;/code&gt; unit.&lt;/p&gt;

&lt;p&gt;You can think of &lt;code&gt;rem&lt;/code&gt; as a multiplier to apply to the default font size. When the browser's font size is set to &lt;code&gt;16px&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1rem&lt;/code&gt; will be &lt;code&gt;16px&lt;/code&gt; (1 * 16px)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1.5rem&lt;/code&gt; will be &lt;code&gt;24px&lt;/code&gt; (1.5 * 16px)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3rem&lt;/code&gt; will be &lt;code&gt;48px&lt;/code&gt; (3 * 16px)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Likewise, when the browser's font size is set to &lt;code&gt;20px&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;1rem&lt;/code&gt; will be &lt;code&gt;20px&lt;/code&gt; (1 * 20px)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;1.5rem&lt;/code&gt; will be &lt;code&gt;30px&lt;/code&gt; (1.5 * 20px)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3rem&lt;/code&gt; will be &lt;code&gt;60px&lt;/code&gt; (3 * 20px)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;&lt;p&gt;Something to keep in mind is that &lt;code&gt;rem&lt;/code&gt; is a &lt;em&gt;relative&lt;/em&gt; font size. It's relative to the root element's font size. &lt;em&gt;This means that you cannot set a default &lt;code&gt;px&lt;/code&gt; value font size in CSS to the &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; tag or to the &lt;code&gt;:root&lt;/code&gt; selector, as it will disable font scaling, even if the rest of your page is using &lt;code&gt;rem&lt;/code&gt; values.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;It's highly encouraged to keep body text size standardized around the &lt;code&gt;1rem&lt;/code&gt; value. While this may seem like a frustrating limitation at first, see it from the user's perspective. Font sizes can, of course, be larger than this for things like headers or callouts, but the primary content of your site should default to this sizing.&lt;/p&gt;

&lt;p&gt;Say site "A" sets their font size to &lt;code&gt;1rem&lt;/code&gt;, and site "B" sets their font size to &lt;code&gt;0.8rem&lt;/code&gt;. When the user switches from "A" to "B", the font size drastically decreases, requiring the user to change their font size. Then, when they switch back to site "A", they're left with too large of font size. By respecting the user's setting of font size, you're ensuring that their experience jumping from site to site is more consistent and a nicer experience.&lt;/p&gt;

&lt;p&gt;Want to learn more about &lt;code&gt;rem&lt;/code&gt; and font sizing? &lt;a href="https://www.24a11y.com/2019/pixels-vs-relative-units-in-css-why-its-still-a-big-deal/" rel="noopener noreferrer"&gt;Take a look at this in-depth blog post that covers even more&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id="keyboard"&gt;Keyboard is King&lt;/h1&gt;

&lt;p&gt;Just as developers have preferences with keyboard or mouse, so too do your end-users. Some people may only be able to utilize the keyboard to navigate the digital world. Not only is keyboard navigation critical for accessibility, but it enables power users of your application to be more efficient as well.&lt;/p&gt;

&lt;p&gt;While you may immediately think of "keyboard shortcuts" to trigger different applications, it's often easy to forget about smaller interactions as well.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;This isn't to say that keyboard shortcuts aren't helpful - they can serve as shorthand for operations that might otherwise take considerable more effort using only the keyboard. Do consider implementing them in your app when they make sense.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Consider a site with a large number of navigation links like &lt;a href="https://www.nytimes.com/" rel="noopener noreferrer"&gt;The New York Times&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fnyt_initial-1024x486.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fnyt_initial-1024x486.png" alt="The initial homepage of New York Times"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Their site has 30+ individual items in their header that you'd need to tab through in order to get to the main portion of the website. Safe to say that most users of the site are likely to want to access that main content quickly. Additionally, users that rely on a screen reader that aren't familiar with the site's layout wouldn't know when to stop tabbing without slogging through every item in the header.&lt;/p&gt;

&lt;p&gt;As such, many sites (including New York Times) include a "Skip to Content" button that doesn't become visible until you've tabbed into it. Unless you were navigating the site by keyboard, you wouldn't know it was there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fnyt_skip-1024x486.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F06%2Fnyt_skip-1024x486.png" alt="A &amp;quot;skip to content&amp;quot; button shown on the New York Times' site"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is far from the only considerations that should be made when considering a site's keyboard navigability, but is a prime example of a solution to a problem that might not be immediately obvious to users that primarily use the mouse.&lt;/p&gt;

&lt;h2 id="focus-indicator"&gt;Focus Indicators&lt;/h2&gt;

&lt;p&gt;Something to keep in mind is that not all keyboard users use screen readers. Because of this, it's important to have an outline around the element you're currently focused on. Without this outline, how would a sighted person know where they are on the page?&lt;/p&gt;

&lt;p&gt;Imagine trying to use your mouse without being able to see your cursor or hover effects on elements — it would be nearly impossible to know what you were doing!&lt;/p&gt;

&lt;p&gt;Luckily, the browser provides a default outline out-of-the-box. That said, some developers unfamiliar with accessibility requirements may disable the outline, as they "don't like the look of the outline when using a mouse" or "think the outline is too obtrusive visually". They often do this by adding an &lt;code&gt;outline: none&lt;/code&gt; rule to the element, which breaks the behavior of the browser.&lt;/p&gt;

&lt;p&gt;Instead, it's suggested to either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Style the outline to be more consistent with your project's visuals (similarly to how The New York times made their outline styling black to match their site)&lt;/li&gt;
&lt;li&gt;Style the element in some other way to indicate focus (avoid only using colors to differentiate, as colorblind users may not be able to distinguish the differences)&lt;/li&gt;
&lt;li&gt;Use JavaScript to disable the behavior when mouse-events are detected (and re-enable if keyboard events are detected)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To learn more about the focus indicator and how to work alongside it, &lt;a href="https://www.a11yproject.com/posts/2013-01-25-never-remove-css-outlines/" rel="noopener noreferrer"&gt;check out this blog post from The A11Y Project&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id="no-automation"&gt;Humans Can’t Be Automated&lt;/h1&gt;

&lt;p&gt;The perception for some is that accessibility is something that can be 1:1 adapted from an existing design. This is often untrue. You may want to add a "Skip to contents" button that only shows up with tabbing for some sites, while the visual order and tab order might need to be flipped for a better experience for screen-reader users. Remember, accessibility is a form of user experience that has to be crafted by hand. Each decision has nuance to it, and there are rarely objectives of which experience is better than others. Because of this, many companies will have dedicated accessibility specialists alongside their design and engineering teams.&lt;/p&gt;

&lt;p&gt;You also need to make sure to test your application as you would any other part of your app. Automation is helpful here, but humans are still critical. We'll touch on this more in a future section.&lt;/p&gt;

&lt;p&gt;If anyone is ever advertising to you that your inaccessible project can be made accessible (or prevent lawsuits) without any changes to your codebase, they're either lying to you or don't understand accessibility.&lt;/p&gt;

&lt;h2 id="eslint"&gt;Assistance is Amicable&lt;/h2&gt;

&lt;p&gt;While full automation will never be possible for improving a project's accessibility, not everyone proposing assistance in the process is trying to sell snake oil.&lt;/p&gt;

&lt;p&gt;For example, &lt;a href="https://github.com/dequelabs/axe-core" rel="noopener noreferrer"&gt;Deque's open-source Axe project&lt;/a&gt; can help identify issues such as common HTML semantic errors, contrast problems, and more. There are even libraries that help integrate Axe into your project's linters, such as one for React called &lt;a href="https://github.com/jsx-eslint/eslint-plugin-jsx-a11y" rel="noopener noreferrer"&gt;&lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, keep in mind that these tools are not infallible and are meant to supplement accessibility experts working with your engineering team, not replace them.&lt;/p&gt;

&lt;h1 id="testing"&gt;Test, Test, Test Again&lt;/h1&gt;

&lt;p&gt;Testing is a critical component of any application release. Whether using automated testing solutions or QA teams, they help ensure that your users are getting the best experience possible without regressions in an application's behavior.&lt;/p&gt;

&lt;p&gt;As a developer working on the frontend, you should be regularly using an assistive technology like a screen reader to analyze your site and navigating your application with only your keyboard. This will help enforce the feedback loop between building the functionality and getting it shipped to users. Make it part of your code review process — have other members of your team test with a screen reader as they would visually analyze new features.&lt;/p&gt;

&lt;p&gt;You're also able to include automated tests that will help with accessibility regressions. Either using &lt;a href="https://kentcdodds.com/blog/write-tests" rel="noopener noreferrer"&gt;integration tests&lt;/a&gt; or end-to-end tests, you can use real-world behavior such as "search for an element with this label" or "tab over to this button" to ensure your application is functioning as intended.&lt;/p&gt;

&lt;p&gt;As mentioned in a previous section, the process to make your app accessible cannot be fully automated. This extends to testing as well. While real-world automated tests are fine and well, you need someone to experience the application on a broader scale to make sure the experience is as fluid as it can be. While a specific component might be accessible by default, perhaps in specific usages, it falls flat. &lt;a href="https://www.w3.org/WAI/planning/statements/" rel="noopener noreferrer"&gt;Displaying an accessibility statement&lt;/a&gt; while transforming your users' reported problems into bug tickets and performing user testing with disabled users are great ways to close the loop with the real people affected.&lt;/p&gt;

&lt;h1 id="features"&gt;Fantastic Features&lt;/h1&gt;

&lt;p&gt;While there is plenty you can do to make existing functionality accessibility friendly, it's often forgotten that a strongly accessible app may opt to add specific functionality for its users with disabilities.&lt;/p&gt;

&lt;p&gt;Some great examples of things like this are sites with lots of user-generated content. For example, Twitter allows its users to &lt;a href="https://help.twitter.com/en/using-twitter/picture-descriptions" rel="noopener noreferrer"&gt;add alternative (alt) text to their uploaded images and GIFs&lt;/a&gt;. Likewise, YouTube has the ability to &lt;a href="https://support.google.com/youtube/answer/2734796?hl=en" rel="noopener noreferrer"&gt;add subtitles and captions&lt;/a&gt; to uploaded videos on their platform.&lt;/p&gt;

&lt;p&gt;Oftentimes, you'll find that these features benefit everyone, not just assistive technology users. You may want to watch a video in a crowded area; with closed captions, that's a much easier sell than trying to hear over others and interrupting everyone around you.&lt;/p&gt;

&lt;h1 id="further-reading"&gt;Radical Research&lt;/h1&gt;

&lt;p&gt;While we've done our best to have this article act as a starting point for accessibility, there's always more to cover. Let's talk about some of the ways you can continue learning more.&lt;/p&gt;

&lt;h2&gt;Terminology&lt;/h2&gt;

&lt;p&gt;During your journey to learn more, you may run into terms that you're not familiar with. Let's take a look at some of the more predominant ones. We'll start this discussion of terminology with a common question:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;What's "A11Y"?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;A11Y is &lt;a href="https://www.a11yproject.com/posts/2017-08-26-a11y-and-other-numeronyms/" rel="noopener noreferrer"&gt;a nymeronym&lt;/a&gt; which stands for "accessibility". It's used as shorthand for the word in conversations about the subject.&lt;/p&gt;

&lt;p&gt;Some other terms that might helpful are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"UI" — "User interface". The visual styling of an app&lt;/li&gt;
&lt;li&gt;"UX" — "User experience". The interaction the user has with the app that defines their experience. This extends to assistive technology&lt;/li&gt;
&lt;li&gt;
"WCAG" — "W3C Accessibility Guidelines", the standard guidelines for applications' accessibility support&lt;/li&gt;
&lt;li&gt;"W3C" — "World Wide Web Consortium", the organization that publishes WCAG&lt;/li&gt;
&lt;li&gt;"ADA" — "Americans with Disabilities Act", regulations in the US for businesses and governments which prohibits discrimination based on disability&lt;/li&gt;
&lt;li&gt;"Alternative text"/"Alt text" — Short text used to describe images and other non-text assets&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Tools&lt;/h2&gt;

&lt;p&gt;People in need of a screen reader have multiple options at their disposal. Just a few of them include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.freedomscientific.com/products/software/jaws/" rel="noopener noreferrer"&gt;JAWS&lt;/a&gt; — An incredibly popular paid Windows screen reader&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.nvaccess.org/" rel="noopener noreferrer"&gt;NVDA&lt;/a&gt; — A Windows screen reader&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.apple.com/accessibility/vision/" rel="noopener noreferrer"&gt;VoiceOver&lt;/a&gt; — The screen reader for iOS and macOS&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.google.com/accessibility/android/answer/6283677?hl=en" rel="noopener noreferrer"&gt;TalkBack&lt;/a&gt; — The screen reader for Android&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's important to keep in mind that just as browsers may have differing behaviors for CSS or JavaScript, so too may these screen readers. Be sure to test with more than one of them as you would with different browsers.&lt;/p&gt;

&lt;p&gt;Screen readers aren't the only accessible tech, however. A small example of them might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.afb.org/node/16207/refreshable-braille-displays" rel="noopener noreferrer"&gt;Braille Displays&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://axesslab.com/switches/" rel="noopener noreferrer"&gt;Switches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Eye_tracking#Assistive_technology" rel="noopener noreferrer"&gt;Eye tracking&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Additional Resources&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://web.dev/a11y-tips-for-web-dev/" rel="noopener noreferrer"&gt;Google's accessibility tips for web developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/design/human-interface-guidelines/accessibility/overview/introduction/" rel="noopener noreferrer"&gt;Apple's accessibility guidelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://webaim.org/" rel="noopener noreferrer"&gt;WebAIM's website with a plethora of resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.a11yproject.com/" rel="noopener noreferrer"&gt;The A11Y Project&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, there are a few sites that contain extensive lists of additional resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.a11yproject.com/resources/" rel="noopener noreferrer"&gt;A11Y project's list of external resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://a11y.me/" rel="noopener noreferrer"&gt;A11Y &amp;amp; Me resource list&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id="conclusion"&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;We hope you've enjoyed learning from our accolade-worthy alliterative headlines.&lt;/p&gt;

&lt;p&gt;There are so many things that we wanted to include in this article but couldn't. Like most parts of engineering, the field of accessible design and the nuances within can be incredibly complex in fringe scenarios. Getting accessibility in a great place for your users takes active effort - just like any other part of building your app. Because of this, we encourage you to do further research on the topic. Don't be afraid to ask questions of community members, either! Many in the community are incredibly helpful and friendly.&lt;/p&gt;

&lt;p&gt;Speaking of community, we'd love to hear your thoughts on this article. Did you learn something from it? Have questions about something accessibility-related? Think we missed something? &lt;a href="https://bit.ly/coderpad-slack" rel="noopener noreferrer"&gt;Join our Slack community&lt;/a&gt; and chat with us or &lt;a href="https://twitter.com/coderpad" rel="noopener noreferrer"&gt;send us a Tweet&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>aria</category>
    </item>
    <item>
      <title>Python List Comprehension – The Comprehensive Guide</title>
      <dc:creator>CoderPad Team</dc:creator>
      <pubDate>Thu, 15 Jul 2021 06:02:14 +0000</pubDate>
      <link>https://forem.com/coderpad/python-list-comprehension-the-comprehensive-guide-2lnb</link>
      <guid>https://forem.com/coderpad/python-list-comprehension-the-comprehensive-guide-2lnb</guid>
      <description>&lt;p&gt;Python list comprehensions allow for powerful and readable list mutations. In this article, we'll learn many different ways in how they can be used and where they're most useful. &lt;/p&gt;

&lt;p&gt;Python is an incredibly powerful language that’s widely adopted across a wide range of applications. As with any language of sufficient complexity, Python enables multiple ways of doing things. However, the community at large has agreed that code should follow a specific pattern: be “Pythonic”. While “Pythonic” is a community term, the official language defines what they call &lt;a href="https://www.python.org/dev/peps/pep-0020/" rel="noopener noreferrer"&gt;“The Zen of Python” in PEP 20&lt;/a&gt;. To quote just a small bit of it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Explicit is better than implicit.&lt;/p&gt;

&lt;p&gt;Simple is better than complex.&lt;/p&gt;

&lt;p&gt;Complex is better than complicated.&lt;/p&gt;

&lt;p&gt;Flat is better than nested.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Introduced in Python 2.0 with &lt;a href="https://www.python.org/dev/peps/pep-0202/" rel="noopener noreferrer"&gt;PEP 202&lt;/a&gt;, list comprehensions help align some of these goals for common operations in Python. Let’s explore how we can use list comprehensions and where they serve the Zen of Python better than alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is List Comprehension?
&lt;/h2&gt;

&lt;p&gt;Let’s say that we want to make an array of numbers, counting up from 0 to 2. We could assign an empty array, use &lt;code&gt;range&lt;/code&gt; to create a generator, then &lt;code&gt;append&lt;/code&gt; to that array using a &lt;code&gt;for&lt;/code&gt; loop&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, we could use list comprehension to shorten that to one line of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confused on the syntax? Let’s outline what’s happening token-by-token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Flist_comp_breakdown.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/.%2Flist_comp_breakdown.png" alt="Breakdown of a list comprehension explained more below"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first and last brackets simply indicate that this is a list comprehension. This is also how I remember that a list comprehension outputs an array - it looks like we’re constructing an array with logic inside.&lt;/p&gt;

&lt;p&gt;Second, we have the “x” before the “for”. This is the return value. This means that if we change the comprehension to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of “0, 1, 2”, we’d get “0, 2, 4”.&lt;/p&gt;

&lt;p&gt;Next up, we have a declaration of a &lt;code&gt;for&lt;/code&gt; loop. This comprises of three separate parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;“for” - the start of the loop&lt;/li&gt;
&lt;li&gt;“x” - declaring the name of the variable to assign in each iteration&lt;/li&gt;
&lt;li&gt;“in” - denoting the start of listening for the iterator&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Finally, we have the &lt;code&gt;range&lt;/code&gt;. This acts as the iterator for the &lt;code&gt;for&lt;/code&gt; loop to iterate through. This can be replaced with anything a &lt;code&gt;for&lt;/code&gt; loop can go through: a list, a tuple, or anything else that implements the iterator interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Are List Comprehension Pythonic?
&lt;/h2&gt;

&lt;p&gt;While it might seem counterintuitive to learn a new syntax for manipulating lists, let’s look at what the alternative looks like. Using &lt;code&gt;map&lt;/code&gt;, we can pass an anonymous function (lambda) to multiply a number by 2, pass the &lt;code&gt;range&lt;/code&gt; to iterate through. However, once this is done, we’re left with a &lt;code&gt;map&lt;/code&gt; object. In order to convert this back to a list, we have to wrap that method in &lt;code&gt;list&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&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="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare this to the list comprehension version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at the comprehension, it’s significantly more readable at a glance. Thinking back to The Zen of Python, “Simple is better than complex,” list comprehensions seem to be more Pythonic than using &lt;code&gt;map&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While others might argue that a “for” loop might be easier to read, the Zen of Python also mentions “Flat is better than nested”. Because of this, list comprehensions for simple usage like this are more Pythonic.&lt;/p&gt;

&lt;p&gt;Now that we’re more familiar with basic usage of list comprehension, let’s dive into some of it’s more powerful capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering
&lt;/h2&gt;

&lt;p&gt;While it might seem like list comprehension is only capable of doing a 1:1 match like &lt;code&gt;map&lt;/code&gt;, you’re actually able to implement logic more similar to &lt;code&gt;filter&lt;/code&gt; to change how many items are in the output compared to what was input.&lt;/p&gt;

&lt;p&gt;If we add an &lt;code&gt;if&lt;/code&gt; to the end of the statement, we can limit the output to only even numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;even_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;#[0, 2, 4, 6, 8]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can of course be combined with the changed mutation value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;double_even_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;#[0, 4, 8, 12, 16]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conditionals
&lt;/h2&gt;

&lt;p&gt;While filtering might seem like the only usage of &lt;code&gt;if&lt;/code&gt; in a list comprehension, you’re able to use them to act as conditionals to return different values from the original.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;number_even_odd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Even&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Odd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="c1"&gt;# ["Even", "Odd", "Even", "Odd"]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind, you could even combine this ternary method with the previous filtering &lt;code&gt;if&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;thirds_even_odd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Even&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Odd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;# [0, 3, 6, 9] after filtering numbers
# ["Even", "Odd", "Even", "Odd"] after ternary to string
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we wanted to expand this code to use full-bodied functions, it would look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;thirds_even_odd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;thirds_even_odd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Even&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;thirds_even_odd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Odd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Nested Loops
&lt;/h2&gt;

&lt;p&gt;While we explained that you’re able to have less items in the output than the input in our “filtering” section, you’re able to do the opposite as well. Here, we’re able to nest two “for” loops on top of each other in order to have a longer output than our initial input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;repeated_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="c1"&gt;# [1, 2, 3, 1, 2, 3]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This logic allows you to iterate through two different arrays and output the final value in the nested loop. If we have to rewrite this, we’d write it out as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;repeated_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;repeated_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows us to nest the loops and keep the logic flat. However, you’ll notice in this example, we’re not utilizing the “x” variable. Let’s change that and do a calculations based on the “x” variable as well:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;numbers_doubled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&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="c1"&gt;# 1, 2, 2, 4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we’ve explored using hard-coded arrays to nest loops, let’s go one level deeper and see how we can utilize list comprehensions in a nested manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nested Comprehensions
&lt;/h2&gt;

&lt;p&gt;There are two facts that we can combine to provide list comprehension with a super power:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You can use lists inside of a list comprehension&lt;/li&gt;
&lt;li&gt;List comprehensions returns lists&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Combining these leads to the natural conclusion that you can nest list comprehensions inside of other list comprehensions.&lt;/p&gt;

&lt;p&gt;For example, let’s take the following logic that, given a two-dimensional list, returns all of the first index items in one list and the second indexed items in a second list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;row_list&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="n"&gt;indexed_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;indexed_row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;row_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;indexed_row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;indexed_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indexed_row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indexed_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# [[1, 3, 5], [2, 4, 6]]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll notice that the first indexed items (&lt;code&gt;1&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;, &lt;code&gt;5&lt;/code&gt;) are in the first array, and the second indexed items (&lt;code&gt;2&lt;/code&gt;, &lt;code&gt;4&lt;/code&gt;, &lt;code&gt;6&lt;/code&gt;) are in the second array.&lt;/p&gt;

&lt;p&gt;Let’s take that and convert it to a list comprehension:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;row_list&lt;/span&gt; &lt;span class="o"&gt;=&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="n"&gt;indexed_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;row_list&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indexed_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# [[1, 3, 5], [2, 4, 6]]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Readable Actions and Other Operators
&lt;/h2&gt;

&lt;p&gt;Something you may have noticed while working with list comprehension is how close some of these operators are to a typical sentence. While basic comprehensions serve this well on their own, they’re advanced by the likes of Python’s other grammatical-style operators. For example, operators may include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;and&lt;/code&gt; - Logical “and”&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;or&lt;/code&gt; - Logical “or”&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;not&lt;/code&gt; - Logical “not”&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;is&lt;/code&gt; - Equality check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;in&lt;/code&gt; - Membership check/second half of &lt;code&gt;for&lt;/code&gt; loop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These can be used for great effect. Let’s look at some options we could utilize:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;vowels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;aeiou&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;word_vowels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;letter&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;letter&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;vowels&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word_vowels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# ['e', 'o']
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively we could check for consonants instead, simply by adding one “not”:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;word_consonants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;letter&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;letter&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;vowels&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;# ['H', 'l', 'l']
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, to showcase boolean logic, we’ll do a slight contrived check for numbers that mod 2 and 3 perfectly but are not 4:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;restricted_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

&lt;span class="n"&gt;safe_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;restricted_number&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# [0, 2, 3]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion &amp;amp; Challenge
&lt;/h2&gt;

&lt;p&gt;We’ve covered a lot about list comprehension in Python today! We’re able to build complex logic into our applications while maintaining readability in most situations. However, like any tool, list comprehension can be abused. When you start including too many logical operations to comfortably read, you should likely migrate away from list comprehension to use full-bodied &lt;code&gt;for&lt;/code&gt; loops.&lt;/p&gt;

&lt;p&gt;For example, given this sandbox code pad of a long and messy list comprehension, how can you refactor to remove all usage of list comprehensions? Avoid using &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt; or other list helpers, either. Simply use nested &lt;code&gt;for&lt;/code&gt; loops and &lt;code&gt;if&lt;/code&gt; conditionals to match the behavior as it was before.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=177671" rel="noopener noreferrer"&gt;See the code challenge here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an open-ended question meant to challenge your skills you’ve learned throughout the article!&lt;/p&gt;

&lt;p&gt;Stuck? Wanting to share your solution? &lt;a href="https://bit.ly/coderpad-slack" rel="noopener noreferrer"&gt;Join our community Slack&lt;/a&gt;, where you can talk about list comprehensions and the challenge in-depth with the CoderPad team!&lt;/p&gt;

</description>
      <category>python</category>
      <category>functional</category>
    </item>
    <item>
      <title>5 Tips for Better Tech Recruiting</title>
      <dc:creator>CoderPad Team</dc:creator>
      <pubDate>Wed, 07 Jul 2021 18:39:57 +0000</pubDate>
      <link>https://forem.com/coderpad/5-tips-for-better-tech-recruiting-17e2</link>
      <guid>https://forem.com/coderpad/5-tips-for-better-tech-recruiting-17e2</guid>
      <description>&lt;p&gt;Tech recruiting is difficult. Interviews are tricky for candidates - and for interviewers. One of the untold challenges of interviewing is knowing how to set up good candidates for success. After all, you want a process that tests the right skills, and filters out the noise that is not  helpful to evaluating candidates.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;This can be done in many ways, but let’s talk about a few today.&lt;/p&gt;

&lt;h2&gt;Don’t Be Afraid To Help&lt;/h2&gt;

&lt;p&gt;Something to keep in mind while interviewing candidates is that they’re just like you and me: people. People that make mistakes from time-to-time or might get stuck on a certain phrasing of a question. This should never leave your mind while tech recruiting.&lt;/p&gt;

&lt;p&gt;Oftentimes, lending a gentle helping hand can be the ticket to a successful interview. It can be as simple as rephrasing the question in a way that points towards the solution, or providing a structural bit of code that needs tweaking in order to be solved.&lt;/p&gt;

&lt;p&gt;This is particularly beneficial for junior engineers, who’s interviews should focus more on “thought process” and “ability to learn and communicate” than existing skill sets. However, even senior engineers can have the solution escape them until it finally clicks with some small assistance.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;While this all might seem counterintuitive to assist a candidate (even in small ways) during an interview, you have to remember that they need support. In their future role with your company, they won’t (and shouldn’t) be working in isolation. Instead, they will have a team to lean on. By giving a small hint here and there, you’re able to understand how they receive feedback and when they need help.&lt;/p&gt;

&lt;h2&gt;Allow for Resources&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, candidates are just people. Because of that, you will never find an all-knowing candidate who only ever relies solely on their existing knowledge to fix an issue (no matter what big-ego Jim says). Time-and-time again we’ve heard from seasoned developers that research and cheat-sheets are part of their daily engineering work. &lt;/p&gt;

&lt;p&gt;While it might not be immediately obvious, knowing how to search for and find the relevant content is incredibly important. Not only that, it’s something that’s developed gradually alongside a developer’s journey - just like any other skill.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;After all, the point of coding interviews as part of tech recruiting is to see how capable a developer is at the job they’re applying for. You want to test in real-world situations, not in an isolated environment that doesn’t represent the daily aspects of the job.&lt;/p&gt;

&lt;h2&gt;Less Algorithms, More Demos&lt;/h2&gt;

&lt;p&gt;Speaking of representing a job in a more realistic light: think about the last time you had a ticket in your backlog that required discussion of tree reversal (or similar algorithm). Now think of the last time you asked a question like that in your interviews. See where I’m going here? I’m not implying that algorithm questions are inherently bad for every position, but in this industry they’ve been used as a stop-gap for more relevant questions. This is the number one complaint I've heard against most tech recruiting.&lt;/p&gt;

&lt;p&gt;Many engineers can attest to being asked algorithmic questions in an interview - only to be working with styling and application state management in their day jobs. The usage of complex algorithms are far-and-few between - especially in front-end engineering. &lt;/p&gt;

&lt;p&gt;Even when algorithms &lt;strong&gt;&lt;em&gt;are&lt;/em&gt;&lt;/strong&gt; relevant, there’s usually a team to discuss with, research to be done, and benchmarking to verify the usage of a given algorithm for key application logic. These discussions can take significantly longer than an hour long interview.&lt;/p&gt;

&lt;p&gt;Not only are these questions rarely representative of the actual job, they’re also easy to cheat with someone with enough free-time to dedicate towards algorithm memorization. Googling “interview algorithm questions” provides over 17 million results. Even the first page of results promises to teach you how to instantly solve dozens of common algorithm questions.&lt;/p&gt;

&lt;p&gt;Not only is possible cheating unhelpful in reflecting a candidate’s problem solving skills, it actively biases your results towards those who’ve put more time into interview prep (which may discourage those who’ve been long-term employees for a single employer). It actively harms those with children or other time constraints that limit their ability to continually practice algorithm questions.&lt;/p&gt;

&lt;p&gt;Even with all of this, I’m only scratching the surface of the &lt;a href="https://coderpad.io/blog/whiteboard-interview-guide/" rel="noopener noreferrer"&gt;issues with algorithm-based “whiteboarding” interviews that’ve been written about before&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Fixing the Problem with Tech Recruiting Questions&lt;/h3&gt;

&lt;p&gt;That said, interview questions are important, so what should we be replacing these algorithm questions with technical assessments?&lt;/p&gt;

&lt;p&gt;Ideally, we should be asking questions based in the real-world. For example, if you’ve got an older class-style React codebase that is being rewritten into functional hooks components, let them do that for the interview!&lt;/p&gt;

&lt;p&gt;In other scenarios, where styling is important to the role, you might want to provide a functioning app and ask the candidate to match an existing design.&lt;/p&gt;

&lt;p&gt;While real-world code samples provide many upsides, setting up a real-world example may take a candidate a little longer to read through the code and orient themselves. How can we reduce the dead-air for interviewers and candidates alike?&lt;/p&gt;

&lt;h2&gt;Take-Homes&lt;/h2&gt;

&lt;p&gt;We at CoderPad are &lt;strong&gt;&lt;em&gt;strong&lt;/em&gt;&lt;/strong&gt; advocates of take-home interviews for technical assessments. While &lt;a href="https://coderpad.io/blog/hire-better-faster-and-in-a-more-human-way-with-take-homes/" rel="noopener noreferrer"&gt;we’ve written about many of the benefits of take-homes before&lt;/a&gt;, we’ll touch on some of the advantages here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lower stress environment for candidate&lt;ul&gt;&lt;li&gt;We’ve heard a lot from the autistic community and those with anxiety that this helps a lot&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;More flexibility and creativity in candidate solutions&lt;/li&gt;
&lt;li&gt;Removes biases&lt;/li&gt;
&lt;li&gt;Kills dead air while candidate is doing initial thought process of a problem&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Level the Playing Field&lt;/h3&gt;

&lt;p&gt;As mentioned previously, time isn’t the same for everyone. Some folks look for work while they’re still working full-time for another employer. Those same people may have kids or other priorities in their lives. This makes time a rare commodity for some. Good tech recruiting should take this into account and help level the playing field.&lt;/p&gt;

&lt;p&gt;A good solution of this can be setting a time limit for take-home projects. However, if a time-limit is softly set and on the honor system, engineers may feel the pressure to go outside of that time-range to add “polish” in order to compete with other candidates. This places us back at the original problem without much done.&lt;/p&gt;

&lt;p&gt;CoderPad allows you to limit the amount of time a candidate is able to spend in assessment. the interview pad Once the timer is done, the candidate is removed from the take-home and their work is submitted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F05%2Fimg_6090d5051dcb2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F05%2Fimg_6090d5051dcb2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I encourage you to keep the time limit to 2 hours max. Any longer and you risk alienating the candidates without that much time to do assessments. Keep in mind - you’re likely not the only role that candidate has applied for.&lt;/p&gt;

&lt;h2&gt;Find Their Speciality&lt;/h2&gt;

&lt;p&gt;Not only do take-homes improve the balance of “stress” vs “capabilities” you look for in an interview, they also allow candidates with specialties focus on their strengths and show you what they’re most capable of.&lt;/p&gt;

&lt;p&gt;Think about it this way: You’re hiring for a team - ideally a team should have a good balance of skills. Even in small-scale applications, there are lots of jobs to do: styling, internal documentation to write, code organization, boilerplate writing, application logic, testing, etc.. While it’s possible to have someone capable of doing more than one of these - it’s impossible to be a true universal expert at all of them at once. Engineers are likely to lean more in some directions than others. Don’t discourage this - it’s what allows a team of diverse people to build a better product through combined individual expertise.&lt;/p&gt;

&lt;h2&gt;Wrap Up&lt;/h2&gt;

&lt;p&gt;Most of these tips are meant to make your tech recruiting more representative of real-world experiences and enable a more diverse pool of candidates to succeed in your process. I hope these tips help give you better insights into your candidates and enable a team that’s more well-rounded,  ultimately bringing more value to your company and teams.&lt;/p&gt;

&lt;p&gt;Hungry for more interviewing tips? Check out our blog about &lt;a href="https://coderpad.io/blog/technical-interviewing-3-actionable-tips-to-hire-well/" rel="noopener noreferrer"&gt;3 other tips for technical interviewing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have more you’d like to add? &lt;a href="https://bit.ly/coderpad-slack" rel="noopener noreferrer"&gt;Join our Slack&lt;/a&gt;, where we talk about interviewing and programming. We’re curious what your tips and tricks are!&lt;/p&gt;

</description>
      <category>recruiting</category>
      <category>interview</category>
      <category>interviewing</category>
    </item>
    <item>
      <title>Master React Unidirectional Data Flow</title>
      <dc:creator>CoderPad Team</dc:creator>
      <pubDate>Sat, 22 May 2021 04:06:57 +0000</pubDate>
      <link>https://forem.com/coderpad/master-react-unidirectional-data-flow-3lm1</link>
      <guid>https://forem.com/coderpad/master-react-unidirectional-data-flow-3lm1</guid>
      <description>&lt;p&gt;As with any form of programming, there are dozens of ways to manage data inside a React application. That said, not all methods are equally capable of scaling. There are some "suggested patterns" for your React applications to follow that will ensure you're not forced to pause in order to reorganize or re-evaluate your existing code when you’re building the application.&lt;/p&gt;

&lt;p&gt;Today, we'll be covering one of the most important structural best practices to follow when building your React applications: Unidirectional data flow.&lt;/p&gt;

&lt;h2&gt;What is Unidirectional Data Flow?&lt;/h2&gt;

&lt;p&gt;Unidirectional data flow is the idea that components should only receiveraise data in one direction. Child components should only call functions from parent components, while parent components should only set/pass data to their children.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://coderpad.io/wp-content/uploads/2021/04/img_6088a07a0be12.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F04%2Fimg_6088a07a0be12-1024x534.png" alt="A graph showing unidirectional data flow being good but bidirectionality being bad"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In order to explain how both of these look in real code, let's start with how a properly unidirectional parent and child component would be written.&lt;/p&gt;

&lt;h2&gt;Unidirectional Demo&lt;/h2&gt;

&lt;p&gt;A great example of a set of components we'll use to demonstrate unidirectionality is a parent "App" component and a child "Form" component.&lt;/p&gt;

&lt;p&gt;Let's take a look at a code sample that follows this unidirectionality first:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=176771" rel="noopener noreferrer"&gt;View the code sample on CoderPad&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see we're passing the onChange and value props to SimpleForm. This keeps our state consolidated inside of the App component rather than split between App and SimpleForm. Once you "submit" the form, SimpleForm calls onDone which changes the state stored inside of App. This in turn causes a re-render of SimpleForm.&lt;/p&gt;

&lt;p&gt;While SimpleForm is displaying the data to the user, the logic itself stays within App. SimpleForm contains no state or application logic; we call components like these "dumb" components. "Dumb" components are utilized for styling and composability, but not for app logic or state.&lt;/p&gt;

&lt;p&gt;This is what a set of proper React components &lt;em&gt;should&lt;/em&gt; look like. This pattern of raising state out of the component itself and leaving "dumb" component comes from the guidance of the React team itself. This pattern is called&lt;a href="https://reactjs.org/docs/lifting-state-up.html" rel="noopener noreferrer"&gt; "lifting state up"&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we have a better understanding of the patterns to follow let's take a look at the wrong way to do things.&lt;/p&gt;

&lt;h2&gt;Breaking from Suggested Patterns&lt;/h2&gt;

&lt;p&gt;Now that we've "lifted" the state, let's drop back down into SimpleForm. We'll start by changing SimpleForm to a class component and adding state.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleForm&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// State is now a part of the SimpleForm component&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&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;value&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Username&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;onChange&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&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="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;onDone&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can use ref in App to access the class methods and state.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&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;simpleRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;()&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;displayTxt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setDisplayTxt&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&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;onDone&lt;/span&gt; &lt;span class="o"&gt;=&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;// Reach into the Ref to access the state of the component instance&lt;/span&gt;
    &lt;span class="nf"&gt;setDisplayTxt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;simpleRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SimpleForm&lt;/span&gt;
        &lt;span class="na"&gt;onDone&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onDone&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;simpleRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;displayTxt&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&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;&lt;a href="https://app.coderpad.io/sandbox?question_id=176773" rel="noopener noreferrer"&gt;View the code sample on CoderPad&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This code works, but has some inherent complexity issues. When you start expanding this component, this idea of separating your state and having to inspect the child reference from the parent makes development more difficult. Let's take a look visually how following the application logic is now more difficult with this pattern.&lt;/p&gt;

&lt;h2&gt;Visualizing the Problem&lt;/h2&gt;

&lt;p&gt;First, let's start by taking a look at the simpleRef component, where the state is "lowered down" to the SimpleForm component:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://coderpad.io/wp-content/uploads/2021/04/img_6088a07cc6cf6.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F04%2Fimg_6088a07cc6cf6-1024x727.png" alt="A complex graph explained more below"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this example, the flow of the application state is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App (and its children, SimpleForm) render&lt;/li&gt;
&lt;li&gt;The user makes changes to the data stored in SimpleForm&lt;/li&gt;
&lt;li&gt;The user triggers the onDone action, which triggers a function in App&lt;/li&gt;
&lt;li&gt;The App onDone method inspects the data from SimpleForm&lt;/li&gt;
&lt;li&gt;Once the data is returned to App, it changes its own data, thus triggering a re-render of App and SimpleForm both&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see from the chart above and the outline of the data flow, one action goes back and forth between the parent and child as App attempts to access the data stored in SimpleForm. This is a prime example of a bi-directional component action. This code sample gets even more complex when onDone is expected to change the state in SimpleForm.&lt;/p&gt;

&lt;p&gt;Now, let's contrast that to the mental model needed to work with unidirectionality enforced.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://coderpad.io/wp-content/uploads/2021/04/img_6088a07e1f014.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderpad.io%2Fwp-content%2Fuploads%2F2021%2F04%2Fimg_6088a07e1f014-1024x727.png" alt="A complex graph explained more below"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App (and its children, SimpleForm) render&lt;/li&gt;
&lt;li&gt;The user makes changes in SimpleForm, the state is raised up to App through callbacks&lt;/li&gt;
&lt;li&gt;The user triggers the onDone action, which triggers a function in App&lt;/li&gt;
&lt;li&gt;The App onDone method already contains all of the data it needs in it's own component, so it simply re-renders App and SimpleForm without any additional logic overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, while the number of steps is similar between these methods (but may not be in a less trivial example), the unidirectional flow is much more streamlined and easier to follow.&lt;/p&gt;

&lt;p&gt;This is why the React core team (and the community at large) strongly suggests you use unidirectionality as often as possible.&lt;/p&gt;

&lt;h2&gt;Conclusion &amp;amp; Challenge&lt;/h2&gt;

&lt;p&gt;Understanding React unidirectional data flow is integral to scaffolding scalable applications. Unidirectionality doesn't just apply to React, either - Angular and Vue applications often require similar patterns for large scale codebases to be easier to follow and more performant.&lt;/p&gt;

&lt;p&gt;Now that we have a deeper understanding of React unidirectional data flow, here's a challenge for you: Refactor the following components to better reflect unidirectionality in this coding pad.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://app.coderpad.io/sandbox?question_id=176774" rel="noopener noreferrer"&gt;View the code sample on CoderPad&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The functionality of the app should be consistent with the previous version. Stuck?&lt;/p&gt;

&lt;p&gt;Start with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move the getNewActivity into a React.useEffect in App&lt;/li&gt;
&lt;li&gt;Move the state.activity into a React.useState in App&lt;/li&gt;
&lt;li&gt;Pass all props to DisplayActivities, making it a "dumb" component&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Still stuck? Maybe you're excited to share your solution?&lt;a href="https://twitter.com/CoderPad" rel="noopener noreferrer"&gt; Send us a Tweet @CoderPad&lt;/a&gt; or&lt;a href="https://bit.ly/coderpad-slack" rel="noopener noreferrer"&gt; ask us in our community Slack&lt;/a&gt;. We'd be excited to hear from you!&lt;/p&gt;

</description>
      <category>react</category>
      <category>dataflow</category>
      <category>unidirectional</category>
    </item>
  </channel>
</rss>
