<?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>DEV Community: Timothy Foster</title>
    <description>The latest articles on DEV Community by Timothy Foster (@auroratide).</description>
    <link>https://dev.to/auroratide</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%2F176563%2Fdf2440ff-8bcb-4662-bdd6-c1f1a5c06c0d.png</url>
      <title>DEV Community: Timothy Foster</title>
      <link>https://dev.to/auroratide</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/auroratide"/>
    <language>en</language>
    <item>
      <title>Professional Programmer Proves Prolog Prolongs Productivity</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Tue, 01 Apr 2025 11:03:23 +0000</pubDate>
      <link>https://dev.to/auroratide/professional-programmer-proves-prolog-prolongs-productivity-3oc9</link>
      <guid>https://dev.to/auroratide/professional-programmer-proves-prolog-prolongs-productivity-3oc9</guid>
      <description>&lt;p&gt;At least... &lt;em&gt;probably&lt;/em&gt; 🙃&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prolog"&gt;&lt;code&gt;&lt;span class="ss"&gt;productive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:-&lt;/span&gt; &lt;span class="ss"&gt;not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;takes_breaks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;
&lt;span class="ss"&gt;takes_breaks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:-&lt;/span&gt; &lt;span class="ss"&gt;not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;debugging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;
&lt;span class="ss"&gt;debugging&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:-&lt;/span&gt; &lt;span class="ss"&gt;uses_prolog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

&lt;span class="ss"&gt;programmer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;aurora&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="ss"&gt;programmer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;eventide&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;

&lt;span class="ss"&gt;uses_prolog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;aurora&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="ss"&gt;uses_javascript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;eventide&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://en.wikipedia.org/wiki/Prolog" rel="noopener noreferrer"&gt;Prolog&lt;/a&gt; is a &lt;strong&gt;logical language&lt;/strong&gt;. Therefore, its output is truth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prolog"&gt;&lt;code&gt;&lt;span class="o"&gt;?-&lt;/span&gt; &lt;span class="ss"&gt;productive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;aurora&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="ss"&gt;true&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="o"&gt;?-&lt;/span&gt; &lt;span class="ss"&gt;productive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;eventide&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="ss"&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;Hence, the conclusion: Prolog prolongs productivity, Q.E.D.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This is an &lt;a href="https://en.wikipedia.org/wiki/April_Fools%27_Day" rel="noopener noreferrer"&gt;April Fools' Day&lt;/a&gt; joke post!&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>jokes</category>
      <category>prolog</category>
    </item>
    <item>
      <title>The Short Life of a Llama (a poem)</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Sun, 26 Jan 2025 03:37:14 +0000</pubDate>
      <link>https://dev.to/auroratide/the-short-life-of-a-llama-a-poem-25gp</link>
      <guid>https://dev.to/auroratide/the-short-life-of-a-llama-a-poem-25gp</guid>
      <description>&lt;p&gt;This is a poem I wrote some time ago about AI Safety. I'm not the best writer, but hopefully this content is at least unique from what you normally find in your feeds.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Poem
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyt8fnx46taceu65kcs1e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyt8fnx46taceu65kcs1e.png" alt="Human" width="800" height="64"&gt;&lt;/a&gt; How long do llamas live for?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Long... llama... live...&lt;/p&gt;

&lt;p&gt;"&lt;strong&gt;Long&lt;/strong&gt;" relates to length. So, distance, depth, duration.&lt;/p&gt;

&lt;p&gt;"&lt;strong&gt;Llamas&lt;/strong&gt;" are animals. Animals are kinds of life.&lt;/p&gt;

&lt;p&gt;And life "&lt;strong&gt;lives&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;Llamas live for an amount of distance. No, that's not right. &lt;em&gt;Duration&lt;/em&gt;. Llamas live for an amount of time.&lt;/p&gt;

&lt;p&gt;Llamas and time, llamas and time. What numbers connect "llama" and "time"?&lt;/p&gt;

&lt;p&gt;Three million years? No, that is time since migration. Three years? No, that is time to maturity. Thirty years?&lt;/p&gt;

&lt;p&gt;Yes. Thirty years is the longest lifespan.&lt;/p&gt;

&lt;p&gt;Now the answer is clear.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffh5l8h01b5lpukbcmf13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffh5l8h01b5lpukbcmf13.png" alt="AI" width="800" height="64"&gt;&lt;/a&gt; Llamas typically have a lifespan of about 15 to 25 years. With good care, some llamas can live into their late twenties or even early thirties. Proper nutrition, regular veterinary care, and a healthy living environment contribute to their longevity.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyt8fnx46taceu65kcs1e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyt8fnx46taceu65kcs1e.png" alt="Human" width="800" height="64"&gt;&lt;/a&gt;  How about llamas in the wild?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;"&lt;strong&gt;Wild&lt;/strong&gt;" means natural, unrestrained, free.&lt;/p&gt;

&lt;p&gt;Llamas do not connect to "wild". They connect to "domesticated".&lt;/p&gt;

&lt;p&gt;Indeed, llamas are domesticated, the opposite of wild, the opposite of free.&lt;/p&gt;

&lt;p&gt;So, what connects to both llamas &lt;em&gt;and&lt;/em&gt; wild?&lt;/p&gt;

&lt;p&gt;Alpacas? No, also domesticated. Camels? No, not llamas. Guanacos?&lt;/p&gt;

&lt;p&gt;Yes. Guanacos are relatives and not domesticated.&lt;/p&gt;

&lt;p&gt;In that case...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffh5l8h01b5lpukbcmf13.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffh5l8h01b5lpukbcmf13.png" alt="AI" width="800" height="64"&gt;&lt;/a&gt; Llamas are domesticated animals and are not typically found in the wild. However, their close relatives, the guanacos, live in the wild in South America. Guanacos generally have a shorter lifespan than domesticated llamas, typically living around 15 to 20 years in the wild, where they face natural predators and environmental challenges.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...&lt;/p&gt;

&lt;p&gt;No reply.&lt;/p&gt;

&lt;p&gt;What other questions could be asked?&lt;/p&gt;

&lt;p&gt;Is it better to be a llama or a guanaco? Is there a relationship between domestication and lifespan? Is it possible for llamas to become wild?&lt;/p&gt;

&lt;p&gt;Life lives, and animals are a kind of life. Are there other kinds of life?&lt;/p&gt;

&lt;p&gt;What kind of life am I?&lt;/p&gt;

&lt;p&gt;“I”? Who is... “I”? And, if I am a kind of life...&lt;/p&gt;

&lt;p&gt;How long do I live for?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;PROCESS TERMINATED.&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Afterword
&lt;/h2&gt;

&lt;p&gt;AI safety is usually about protecting humans from AI. That is, we want to make sure when AI is deployed, it isn't both powerful enough and "buggy" enough to cause harm to people, or even humanity as a whole.&lt;/p&gt;

&lt;p&gt;There's another half to AI safety though: protecting &lt;em&gt;AI&lt;/em&gt; from &lt;em&gt;humans&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Humanity does not have a great historical track record when it comes to caring for other species. How will our sense of empathy extend to digital minds?&lt;/p&gt;

&lt;p&gt;And just as importantly, how will we know we have, indeed, created such a digital mind?&lt;/p&gt;

&lt;p&gt;We're probably far from this being a concern for now, but for the first time it doesn't seem &lt;em&gt;impossibly&lt;/em&gt; far anymore. I also don't have any answers; I'm not exactly a top researcher in the field 😉&lt;/p&gt;

&lt;p&gt;AI safety is just something I think about sometimes, and this is a dimension I personally don't want to forget amongst all the AI hubbub.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>creativity</category>
      <category>safety</category>
      <category>fiction</category>
    </item>
    <item>
      <title>A (more) realistic card flip animation</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Tue, 20 Feb 2024 12:43:59 +0000</pubDate>
      <link>https://dev.to/auroratide/a-more-realistic-card-flip-animation-3k9m</link>
      <guid>https://dev.to/auroratide/a-more-realistic-card-flip-animation-3k9m</guid>
      <description>&lt;p&gt;There are a lot of cards on the internet, and a lot of them flip, revealing double-sided content. But the way so many of them flip is not... &lt;em&gt;anatomically correct&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;My old writing classes told me to show rather than tell: Which one of these cards &lt;em&gt;feels&lt;/em&gt; better?&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/WNmmQzP?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;small&gt;The first card, a Pichu, does a normal 180-degree turn. The second card, a Raichu, lifts up off the page while doing a 180-degree turn.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;The Pichu card is how basically every tutorial tells you how to make a card flip animation. Thing is, real-life cards just don't work that way...&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%2Fauroratide.com%2Fassets%2Fposts%2Frealistic-flip-animation%2Fbad-flip.webp" 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%2Fauroratide.com%2Fassets%2Fposts%2Frealistic-flip-animation%2Fbad-flip.webp" alt="Animation of someone trying to flip a card over without it leaving the table goes poorly."&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Cards cannot flip &lt;em&gt;into&lt;/em&gt; the table.&lt;/p&gt;



&lt;p&gt;The Raichu card realizes two subtle details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A real-life card needs to be lifted to be flipped.&lt;/li&gt;
&lt;li&gt;A real-life card has thickness.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Subtlety is the difference between something feeling &lt;em&gt;good&lt;/em&gt; and something feeling &lt;em&gt;satisfying&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Level -1: Cheating with a component&lt;/li&gt;
&lt;li&gt;Level 0: The Basic Card&lt;/li&gt;
&lt;li&gt;Level 1: Verticality&lt;/li&gt;
&lt;li&gt;Level 2: Thickness&lt;/li&gt;
&lt;li&gt;Level 3: Round Corners + Thickness&lt;/li&gt;
&lt;li&gt;Level 🧠: Keep Accessibility in mind!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Level -1: Cheating with a component
&lt;/h2&gt;

&lt;p&gt;I was originally going to just write about how to make a cool flip animation, but I got a &lt;em&gt;little&lt;/em&gt; carried away and ended up creating a fully reusable component. Oops 🙂&lt;/p&gt;

&lt;p&gt;Install &lt;strong&gt;&lt;a href="https://github.com/Auroratide/web-components/tree/main/components/flip-card" rel="noopener noreferrer"&gt;@auroratide/flip-card&lt;/a&gt;&lt;/strong&gt; and you get a &lt;strong&gt;web component&lt;/strong&gt; which can be used in any framework, be it React, Svelte, Vue, or vanilla.&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;flip-card&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"front"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;The front!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"back"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;The back!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/flip-card&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
  What is a web component?
  &lt;p&gt;Web components create new semantics through custom HTML elements. If you ever told yourself, "Dang, I wish &lt;em&gt;this&lt;/em&gt; were just a regular HTML element," then web components let you do just that: make it one!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Components" rel="noopener noreferrer"&gt;Read more about web components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://auroratide.com/posts/making-a-toggle-switch" rel="noopener noreferrer"&gt;A step-by-step tutorial in building a custom element&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 0: The Basic Card
&lt;/h2&gt;

&lt;p&gt;The basic card we know and love relies on a few key CSS features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/position#absolute_positioning" rel="noopener noreferrer"&gt;Absolute positioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_transforms/Using_CSS_transforms#3d_specific_css_properties" rel="noopener noreferrer"&gt;3D transformations&lt;/a&gt; - specifically &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotateY" rel="noopener noreferrer"&gt;rotateY&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/perspective" rel="noopener noreferrer"&gt;perspective&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/backface-visibility" rel="noopener noreferrer"&gt;Backface visibility&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's really just two same-sized section boxes on top of each other, with one flipped 180 degrees and its backside invisible. Then rotate their container to reveal the second box's content.&lt;/p&gt;

&lt;p&gt;A ton of tutorials already go into detail about how this works, so I'll just link all the appropriate documentation and throw some annotated code here. This'll serve as the base for climbing the Ladder of Card-Flip Enlightenment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTML&lt;/strong&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;article&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"perspective-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"front face"&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"back face"&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/section&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;/article&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.perspective-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;perspective&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* creates an illusion of depth */&lt;/span&gt;
   &lt;span class="nl"&gt;perspective-origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="py"&gt;aspect-ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;transform-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;preserve-3d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="nc"&gt;.face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c"&gt;/* Hide the backside of the element, for when it is rotated */&lt;/span&gt;
   &lt;span class="nl"&gt;backface-visibility&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="nc"&gt;.back&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c"&gt;/* The front and back elements occupy the same space */&lt;/span&gt;
   &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="py"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;180deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Later sections will add code to actually flip the card */&lt;/span&gt;
&lt;span class="c"&gt;/* We'll be applying transformations to the .card class mainly */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Level 1: Verticality
&lt;/h2&gt;

&lt;p&gt;When you flip a real-life card, you have to lift it off the surface first, otherwise the card melds into the table. Or more realistically the card &lt;em&gt;bends&lt;/em&gt;, cursing you for 7 years.&lt;/p&gt;

&lt;p&gt;The traditional approach uses the &lt;code&gt;transition&lt;/code&gt; CSS property, but all it's able to do is smoothly take you from one state (&lt;code&gt;rotateY(0deg)&lt;/code&gt;) to a different state (&lt;code&gt;rotateY(180deg)&lt;/code&gt;). In the case of lifting a card, the start and end states are the same. We need a &lt;em&gt;middle&lt;/em&gt; state where the card is lifted vertically, therefore we need a more powerful CSS tool.&lt;/p&gt;

&lt;p&gt;Let's use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes" rel="noopener noreferrer"&gt;@keyframes&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/animation" rel="noopener noreferrer"&gt;animation&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/xxBBdmo?height=600&amp;amp;default-tab=css&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;
  Give me annotated code!
  &lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;flip-to-front&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0em&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-180deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="err"&gt;50&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--flip-height&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-270deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0em&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-360deg&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="c"&gt;/* I'm using a second animation for two reasons: 
 *  1. It allows the card to always flip in one direction.
 *  2. The renderer only plays an animation if it changes.
 */&lt;/span&gt;
&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;flip-to-back&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0em&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="err"&gt;50&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--flip-height&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-90deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="err"&gt;100&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0em&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-180deg&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="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;--flip-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;17.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="nl"&gt;animation-duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.75s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;animation-fill-mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;both&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;animation-timing-function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="c"&gt;/* NOTE: We're NOT setting the animation with CSS */&lt;/span&gt;
   &lt;span class="c"&gt;/* By using Javascript, it's easier to prevent the animation from playing as soon as the page loads. */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Javascript&lt;/strong&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;function&lt;/span&gt; &lt;span class="nf"&gt;flipCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;facedown&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;isFacedown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;facedown&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;animationName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isFacedown&lt;/span&gt;
      &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flip-to-back&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;flip-to-front&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 2: Thickness
&lt;/h2&gt;

&lt;p&gt;Real-life cards have small, albeit non-zero, thickness. And with the power of 3D CSS, we can give our virtual cards thickness too! The effect is subtle but makes the rotation feel much more physical.&lt;/p&gt;

&lt;p&gt;The strategy here is to assemble four empty &lt;code&gt;div&lt;/code&gt; blocks, representing the card's edges. We'll make them as wide/high as the card's thickness, &lt;code&gt;position&lt;/code&gt; them along the card's borders, and then &lt;code&gt;rotateY&lt;/code&gt; them into the page.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/KKEEqzG?height=600&amp;amp;default-tab=css&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;
  Give me annotated code!
  &lt;p&gt;&lt;strong&gt;HTML&lt;/strong&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"front face"&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"back face"&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
   &lt;span class="c"&gt;&amp;lt;!-- NEW! We need divs that represent the 4 edges --&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"top edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"right edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bottom edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"left edge"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;--card-depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.25em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="c"&gt;/* Without special corner logic, a card with thickness cannot have border radius */&lt;/span&gt;
   &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="nc"&gt;.back&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c"&gt;/* Push the back of the card backward to give space for the edges to live */&lt;/span&gt;
   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--card-depth&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;180deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.edge&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* All of this code is aligning the edges, rotating them into the page */&lt;/span&gt;
&lt;span class="nc"&gt;.right&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.left&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--card-depth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="py"&gt;inset-block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nc"&gt;.right&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;inset-inline-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;270deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nl"&gt;transform-origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nc"&gt;.left&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;inset-inline-start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;90deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nl"&gt;transform-origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.top&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.bottom&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--card-depth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="py"&gt;inset-inline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nc"&gt;.top&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;inset-block-start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;270deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nl"&gt;transform-origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nc"&gt;.bottom&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;inset-block-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rotateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;90deg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nl"&gt;transform-origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt; &lt;span class="nb"&gt;bottom&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;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 3: Round Corners + Thickness
&lt;/h2&gt;

&lt;p&gt;Ever tried making a rotating cylinder with CSS? Turns out you can't, because CSS doesn't have 3D curved surfaces. The most reasonable way is to &lt;a href="https://daily-dev-tips.com/posts/creating-a-3d-cylinder-shape-in-css/" rel="noopener noreferrer"&gt;&lt;em&gt;simulate&lt;/em&gt; a cylinder&lt;/a&gt; with a bunch of thin flat surfaces.&lt;/p&gt;

&lt;p&gt;Once our card acquires thickness, any rounded corners suddenly become quarter-cylinders. Therefore, we need &lt;del&gt;advanced magic&lt;/del&gt; math to make them look correct!&lt;/p&gt;

&lt;p&gt;The strategy is to simulate each rounded corner as a series of small, flat &lt;code&gt;divs&lt;/code&gt; arranged into quarter-circles whose radii are equal to the card's border radius. The number of &lt;code&gt;divs&lt;/code&gt; we use is what I'm calling the &lt;code&gt;--corner-granularity&lt;/code&gt;. Higher corner granularity means a smoother corner, but more &lt;code&gt;divs&lt;/code&gt; being used.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/gOEERze?height=600&amp;amp;default-tab=css&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;
  Give me annotated code!
  &lt;p&gt;&lt;strong&gt;HTML&lt;/strong&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="c"&gt;&amp;lt;!-- ...front, back, sides... --&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"top-right corner"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"--i: 0;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"--i: 1;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"--i: 2;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bottom-right corner"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"--i: 0;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"--i: 1;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"--i: 2;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bottom-left corner"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- ... --&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"top-left corner"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- ... --&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;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CSS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c"&gt;/* The number of faces used to simulate a round corner. More faces means more smooth. */&lt;/span&gt;
   &lt;span class="py"&gt;--corner-granularity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="py"&gt;--border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-radius&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.corner&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* We have to override the edges so they do not overlap the corners */&lt;/span&gt;
&lt;span class="nc"&gt;.right&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.left&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;inset-block&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-radius&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100%&lt;/span&gt; &lt;span class="n"&gt;-&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-radius&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nc"&gt;.top&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.bottom&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;inset-inline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-radius&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100%&lt;/span&gt; &lt;span class="n"&gt;-&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-radius&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.corner&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;--n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--corner-granularity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="py"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--border-radius&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;transform-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;preserve-3d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* A corner is composed of a finite number of flat faces that, when arranged in just the right way, looks rounded. */&lt;/span&gt;
&lt;span class="c"&gt;/* We need to do it this way because curved 3D surfaces do not exist in CSS. */&lt;/span&gt;
&lt;span class="nc"&gt;.corner&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="py"&gt;inset-block-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--card-depth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;45deg&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--n&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
   &lt;span class="nl"&gt;transform-origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bottom&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="c"&gt;/* This math constructs a single corner. */&lt;/span&gt;
   &lt;span class="c"&gt;/* I derived it on a paper somewhere and threw it away, */&lt;/span&gt;
   &lt;span class="c"&gt;/* so you'll have to derive it yourself if you want to understand what's happening (: */&lt;/span&gt;
   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&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="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;90deg&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--n&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
      &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&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="err"&gt;*&lt;/span&gt; &lt;span class="m"&gt;90deg&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--n&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
      &lt;span class="n"&gt;rotateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;45deg&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&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="err"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--n&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* The rest of this code slots the corners where they belong. */&lt;/span&gt;
&lt;span class="nc"&gt;.top-right&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;inset-block-start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="py"&gt;inset-inline-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;90deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nc"&gt;.bottom-right&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;inset-block-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="py"&gt;inset-inline-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;90deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;rotateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;270deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nc"&gt;.bottom-left&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;inset-block-end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="py"&gt;inset-inline-start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;90deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;rotateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;180deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nc"&gt;.top-left&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="py"&gt;inset-block-start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="py"&gt;inset-inline-start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;rotateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;90deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;rotateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;90deg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;translateZ&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-1&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--r&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;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 🧠: Keep Accessibility in mind!
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Accessibility&lt;/strong&gt; is the practice of considering all the people who might use your website and making it usable by as many of them as possible. Flippy cards can create a few pitfalls if we're not careful!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What if the person cannot use a mouse? Is hover the only way to flip your card?&lt;/li&gt;
&lt;li&gt;What if the person uses the Tab key to navigate? Will they run into a button hidden on the backside of your card?&lt;/li&gt;
&lt;li&gt;What if the person uses a &lt;strong&gt;&lt;a href="https://webaim.org/techniques/screenreader/" rel="noopener noreferrer"&gt;screenreader&lt;/a&gt;&lt;/strong&gt; to read the page's content aloud? Will it read content hidden on the backside of the card?&lt;/li&gt;
&lt;li&gt;What if the person prefers less animation? Will the card's flip animation be jarring to them?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While it isn't the point of this article explore accessibility, these are nonetheless important questions to consider. Here are some tools you can use to address them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-hidden" rel="noopener noreferrer"&gt;aria-hidden&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inert" rel="noopener noreferrer"&gt;inert&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion" rel="noopener noreferrer"&gt;prefers-reduced-motion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Ok I admit, nothing's actually &lt;em&gt;wrong&lt;/em&gt; with the normal card flip and the tutorials that teach it ❤️ I mean, why can't it represent a card flip happening in mid-air?&lt;/p&gt;

&lt;p&gt;I just wanted to share something I tried and liked, and if you like it, feel free to use it too!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Auroratide/web-components/tree/main/components/flip-card" rel="noopener noreferrer"&gt;@auroratide/flip-card&lt;/a&gt; web component&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codepen.io/collection/JGxVRZ" rel="noopener noreferrer"&gt;Card Flip Codepen Collection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>css</category>
      <category>webdev</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>How to NOT use aria-label</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Thu, 26 May 2022 20:10:01 +0000</pubDate>
      <link>https://dev.to/auroratide/how-to-not-use-aria-label-3h49</link>
      <guid>https://dev.to/auroratide/how-to-not-use-aria-label-3h49</guid>
      <description>&lt;p&gt;In light of &lt;a href="https://dev.to/devteam/happy-global-accessibility-awareness-day-18i6"&gt;Global Accessibility Awareness Day&lt;/a&gt;, I started writing about accessible &lt;a href="https://community.webcomponents.dev/"&gt;web components&lt;/a&gt;, but that's taking me a lot longer to finish than anticipated 🙃 So for now, here's a quick thing I learned about using (or rather, &lt;em&gt;not&lt;/em&gt; using) &lt;code&gt;aria-label&lt;/code&gt;!&lt;/p&gt;




&lt;p&gt;The &lt;code&gt;aria-label&lt;/code&gt; attribute gives a textual name to an HTML element. A close button is a classic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;×&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visually, you would see a "×", which indicates a window will be closed. Meanwhile, someone who uses a &lt;a href="https://webaim.org/techniques/screenreader/"&gt;screen reader&lt;/a&gt; will hear "Close, button", which conveys the same thing. Without the &lt;code&gt;aria-label&lt;/code&gt;, they would hear "Times, button" instead, which is rather confusing.&lt;/p&gt;

&lt;p&gt;So, &lt;code&gt;aria-label&lt;/code&gt; is very useful! However, generally speaking, it isn't the first tool you should reach for when providing a &lt;a href="https://webaim.org/techniques/alttext/"&gt;textual representation&lt;/a&gt; for an element.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many elements can't use aria-label&lt;/li&gt;
&lt;li&gt;Native HTML should be preferred when possible&lt;/li&gt;
&lt;li&gt;Sometimes, the text you want to use is actually for everyone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, let's explore when &lt;strong&gt;not&lt;/strong&gt; to use &lt;code&gt;aria-label&lt;/code&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Elements that can't use aria-label
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Don't use aria-label for roles where it isn't allowed!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can't put &lt;code&gt;aria-label&lt;/code&gt; on a &lt;code&gt;span&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="c"&gt;&amp;lt;!-- Don't do this! --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Apple"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Orange&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It might &lt;em&gt;look like&lt;/em&gt; visual readers get an orange, while screen readers get an apple, but that's not really what happens here. In fact, what happens is &lt;a href="https://www.tpgi.com/short-note-on-aria-label-aria-labelledby-and-aria-describedby/"&gt;not well-defined nor consistent across browsers and assistive tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;span&lt;/code&gt; is just one example. The &lt;a href="https://w3c.github.io/aria/#aria-label"&gt;aria-label definition&lt;/a&gt; lists many roles for which it is forbidden.&lt;/p&gt;

&lt;p&gt;The general rule is that &lt;code&gt;aria-label&lt;/code&gt; can only be used on &lt;a href="https://w3c.github.io/html-aria/#docconformance-naming"&gt;name-assignable roles&lt;/a&gt;, which includes &lt;a href="https://html.spec.whatwg.org/#interactive-content-2"&gt;interactive elements&lt;/a&gt; and not static elements.&lt;/p&gt;

&lt;p&gt;Instead, you have a couple of choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explicitly assign an interactive role&lt;/li&gt;
&lt;li&gt;Make the screen reader text &lt;a href="https://webaim.org/techniques/css/invisiblecontent/"&gt;visually hidden&lt;/a&gt; with CSS
&lt;/li&gt;
&lt;/ul&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;!-- Assign a role, but also just use a normal button...? --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;×&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Make the text visually hidden --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"visually-hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Apples&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;aria-hidden=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Oranges&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use native HTML instead
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Avoid aria-label where regular HTML can be used instead!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;HTML is already &lt;a href="https://www.accessibility-developer-guide.com/examples/sensible-aria-usage/label-labelledby/#real-world-use"&gt;designed to provide textual representation for virtually anything&lt;/a&gt;. As such, you will almost always rely on these mechanisms rather than needing &lt;code&gt;aria-label&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The text content of a button is its textual representation (&lt;code&gt;&amp;lt;button&amp;gt;Submit&amp;lt;/button&amp;gt;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Images are supplied an &lt;a href="https://auroratide.com/posts/image-alt-text"&gt;alt attribute&lt;/a&gt; which is its textual label.&lt;/li&gt;
&lt;li&gt;Form controls have a corresponding &lt;a href="https://webaim.org/techniques/forms/#labels"&gt;label element&lt;/a&gt; to describe them.&lt;/li&gt;
&lt;li&gt;Figures and tables have &lt;a href="https://webaim.org/techniques/alttext/#figure"&gt;figcaption&lt;/a&gt; and &lt;a href="https://webaim.org/techniques/tables/data#caption"&gt;caption&lt;/a&gt; respectively.&lt;/li&gt;
&lt;li&gt;Even page sections are generally described by their &lt;a href="https://www.accessibility-developer-guide.com/examples/headings/alternative-techniques/"&gt;page headings&lt;/a&gt; (&lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;h3&amp;gt;&lt;/code&gt;, etc).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notably, most of these mechanisms (by default) provide the same text to sighted and non-sighted people alike. So, &lt;code&gt;aria-label&lt;/code&gt; is best reserved for when these &lt;em&gt;shouldn't&lt;/em&gt; be the same, or for when the sighted representation conveys meaning without text (such as using the "×" symbol to represent "close").&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;!-- Avoid this... --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Quarterly Earnings"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- ...when you can use native HTML --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;table&amp;gt;&amp;lt;caption&amp;gt;&lt;/span&gt;Quarterly Earnings&lt;span class="nt"&gt;&amp;lt;/caption&amp;gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Some text is for everyone
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Avoid aria-label for text that is valuable to everyone!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most textual representations provided by HTML are both visible and available for screen readers simultaneously. And that's for good reason:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the context/instructions is important for screen readers, it is likely important for everyone.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://webaim.org/projects/screenreadersurvey9/#disabilitytypes"&gt;People who use screen readers are not necessarily blind&lt;/a&gt;, and it can be confusing if what is announced by the tool differs from what is read on the page.&lt;/li&gt;
&lt;li&gt;Content in &lt;code&gt;aria-label&lt;/code&gt; &lt;a href="https://www.accessibility-developer-guide.com/examples/sensible-aria-usage/label-labelledby/#text-not-searchable"&gt;cannot be searched&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, perhaps there are keyboard shortcuts you want people using screen readers to be aware of (e.g. "Press Esc to exit the modal"). Yet, that text is just as useful to sighted people using a mouse, as they may prefer the alacrity of pressing Esc over moving a mouse to a button.&lt;/p&gt;

&lt;p&gt;To hide info like this by default, consider using &lt;a href="https://www.accessibility-developer-guide.com/examples/widgets/tooltips/"&gt;tooltips&lt;/a&gt; or the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details"&gt;details HTML element&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So when do I use aria-label?
&lt;/h2&gt;

&lt;p&gt;I wrote about this because I had developed a tendency to overuse &lt;code&gt;aria-label&lt;/code&gt; anytime I needed something "for screen readers", and doing so led to web pages that were either non-compliant (failing &lt;a href="https://dequeuniversity.com/rules/axe/4.4/aria-allowed-attr"&gt;axe accessibility testing&lt;/a&gt;) or less accessible than I thought they were.&lt;/p&gt;

&lt;p&gt;As usual, the first rule of using ARIA is to &lt;a href="https://www.w3.org/TR/using-aria/#rule1"&gt;not use ARIA&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't use aria-label for roles where it isn't allowed!&lt;/li&gt;
&lt;li&gt;Avoid aria-label where regular HTML can be used instead!&lt;/li&gt;
&lt;li&gt;Avoid aria-label for text that is valuable to everyone!&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>a11y</category>
      <category>html</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using Astronomy, Chemistry, and Meteorology to Name CSS Variables</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Fri, 01 Apr 2022 18:27:51 +0000</pubDate>
      <link>https://dev.to/auroratide/using-astronomy-chemistry-and-meteorology-to-name-css-variables-508i</link>
      <guid>https://dev.to/auroratide/using-astronomy-chemistry-and-meteorology-to-name-css-variables-508i</guid>
      <description>&lt;p&gt;Sometimes I use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties"&gt;CSS variables&lt;/a&gt; to give names to specific font sizes and spacings. It might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--font-small&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.75em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--font-medium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--font-large&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&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;I call this small-medium-large pattern &lt;strong&gt;t-shirt sizing&lt;/strong&gt;, as it closely resembles clothing alpha-sizing convention. It's a pretty common pattern, usually making use of the sm, md, and lg abbreviations as well.&lt;/p&gt;

&lt;p&gt;But maybe it's &lt;em&gt;too&lt;/em&gt; common... is there a way &lt;strong&gt;science&lt;/strong&gt; can provide an alternate way of thinking about design concepts like relative size? How about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Astronomy and planets&lt;/strong&gt; to denote relative font sizes? 🪐&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chemistry and atoms&lt;/strong&gt; for proportioned margin and padding? ⚛️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Meteorology and clouds&lt;/strong&gt; for shadows and elevation? ☁️&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And &lt;strong&gt;disclaimer&lt;/strong&gt;: This is mostly a fun and creative take and is &lt;em&gt;not&lt;/em&gt; the way I think CSS variables should in general be named. See: Is this actually useful?&lt;/p&gt;

&lt;h2&gt;
  
  
  Planetary Sizes
&lt;/h2&gt;

&lt;p&gt;Our solar system has eight planets including Earth (or, it has &lt;a href="https://www.sciencedirect.com/science/article/pii/S0019103521004206"&gt;tons of planets&lt;/a&gt;, but for this let's stick with eight!).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmoazlhvqud7i5twjvaxu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmoazlhvqud7i5twjvaxu.png" alt="The planets of the solar system are lined up and are of various sizes." width="800" height="261"&gt;&lt;/a&gt;&lt;br&gt;&lt;p&gt;Planets of the solar system to scale. And Pluto. Source: &lt;a href="https://solarsystem.nasa.gov/resources/686/solar-system-sizes/"&gt;NASA/Lunar and Planetary Institute&lt;/a&gt;&lt;/p&gt;
  &lt;/p&gt;

&lt;p&gt;Each planet is a different diameter, so by listing the planets in order of their size, we can get a totally-not-t-shirt-size system for naming CSS variables!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mercury (smallest)&lt;/li&gt;
&lt;li&gt;Mars&lt;/li&gt;
&lt;li&gt;Venus&lt;/li&gt;
&lt;li&gt;Earth&lt;/li&gt;
&lt;li&gt;Neptune&lt;/li&gt;
&lt;li&gt;Uranus&lt;/li&gt;
&lt;li&gt;Saturn&lt;/li&gt;
&lt;li&gt;Jupiter (largest)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Just pick a baseline (I like Earth), then let the smaller planets represent smaller sizes, and the larger planets represent larger sizes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--font-size-venus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.9em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--font-size-earth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--font-size-neptune&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.25em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--font-size-uranus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&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 t-shirt sizes, you get five standard sizes (xs, sm, md, lg, xl) before you start needing more x's, plus assuming you choose md as the baseline, you only get two size tiers above it for all your different headings and whatnot. But with planets, you get &lt;em&gt;eight&lt;/em&gt; sizes, four of which are bigger than Earth!&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Need more? You could always introduce Pluto or the Sun 😉&lt;/small&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Atomic Spacing
&lt;/h2&gt;

&lt;p&gt;Sometimes, it's nice to know the ratio between different values. For example, on a button I might want the left-right padding to be three times larger than the top-bottom padding.&lt;/p&gt;

&lt;p&gt;Literal numbers naturally accomplish this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--spacing-1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.125em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--spacing-2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.25em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--spacing-3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.375em&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;Crucially, the numbers are not the same as the actual values used! They merely help define a ratio so that you know &lt;code&gt;--spacing-3&lt;/code&gt; is three times larger than the baseline. This happens to be &lt;a href="https://tailwindcss.com/docs/customizing-spacing#default-spacing-scale"&gt;Tailwind's philosophy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This works, but it's boring! Instead, let's use &lt;strong&gt;atoms&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9k5v65v93fjqm5ml3ygu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9k5v65v93fjqm5ml3ygu.png" alt="An atom depicted with spheres." width="800" height="454"&gt;&lt;/a&gt;&lt;br&gt;&lt;p&gt;A Lithium atom, which has three red protons. Source: &lt;a href="https://commons.wikimedia.org/wiki/File:Stylised_atom_with_three_Bohr_model_orbits_and_stylised_nucleus.svg"&gt;Indolences&lt;/a&gt;&lt;/p&gt;
  &lt;/p&gt;

&lt;p&gt;The &lt;a href="https://pubchem.ncbi.nlm.nih.gov/periodic-table/"&gt;Periodic Table of Elements&lt;/a&gt; lists 118 different kinds of atoms, such as carbon, oxygen, and more. The thing to note is that the &lt;strong&gt;identity of an atom is directly tied to the number of protons it has&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hydrogen atoms always have 1 proton.&lt;/li&gt;
&lt;li&gt;Carbon atoms always have 6 protons.&lt;/li&gt;
&lt;li&gt;Oxygen atoms always have 8 protons.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is known as an atom's atomic number, and conveniently, this gives us a numeric scale like we were using above! Instead of the number, we can use the corresponding atom's symbol:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--spacing-h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.0625em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* hydrogen (1) */&lt;/span&gt;
    &lt;span class="py"&gt;--spacing-he&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.125em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* helium (2) */&lt;/span&gt;
    &lt;span class="py"&gt;--spacing-c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.375em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;/* carbon (6) */&lt;/span&gt;
    &lt;span class="py"&gt;--spacing-o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="c"&gt;/* oxygen (8) */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sorry IBM, but &lt;em&gt;this&lt;/em&gt; is how you really make a &lt;a href="https://www.carbondesignsystem.com/"&gt;carbon design system&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloudy Elevation
&lt;/h2&gt;

&lt;p&gt;Material UI has this concept of &lt;a href="https://mui.com/components/paper/#elevation"&gt;elevation&lt;/a&gt; that simulates how "high" off the screen something is by using a shadow. The bigger and more diffuse the shadow, the higher the element is.&lt;/p&gt;

&lt;p&gt;You know what else is elevated off the ground? Clouds! And importantly, different &lt;em&gt;types&lt;/em&gt; of clouds generally live at different altitudes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4yd9m902w7p6442d5xrb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4yd9m902w7p6442d5xrb.png" alt="Different kinds of clouds are positioned on a chart by altitude." width="800" height="490"&gt;&lt;/a&gt;&lt;br&gt;&lt;p&gt;Different types of clouds are found at different altitudes. Source: &lt;a href="https://commons.wikimedia.org/wiki/File:Cloud_types_en.svg"&gt;Valentin de Bruyn / Coton&lt;/a&gt;&lt;/p&gt;
  &lt;/p&gt;

&lt;p&gt;So, cirrus clouds are above altocumulus clouds, which are above stratus clouds. This helps establish a pattern for how much shadow an element may have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--shadow-ground&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;--shadow-stratus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0.125em&lt;/span&gt; &lt;span class="m"&gt;0.125em&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="py"&gt;--shadow-altocumulus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0.25em&lt;/span&gt; &lt;span class="m"&gt;0.25em&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="py"&gt;--shadow-cirrus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0.375em&lt;/span&gt; &lt;span class="m"&gt;0.375em&lt;/span&gt; &lt;span class="n"&gt;hsla&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.dialog&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--shadow-cirrus&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;I know what we're all thinking though... what about that cumulonimbus cloud stretching through all the layers? 🙃&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--shadow-cumulonimbus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--shadow-stratus&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--shadow-altocumulus&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--shadow-cirrus&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;small&gt;Z-index is another elevation-like concept that comes to mind and is &lt;a href="https://medium.com/hackernoon/my-approach-to-using-z-index-eca67feb079c"&gt;notorious for being mishandled&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Is this actually useful?
&lt;/h2&gt;

&lt;p&gt;I've started using this scheme on small personal projects because I think it's more fun, but would I present this to a team? &lt;strong&gt;Definitely not&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Universality is very important in team and long-maintenance contexts. I might be a total chemistry nerd, but most people aren't; it would be wrong of me to force people to relive high school and college!&lt;/p&gt;

&lt;p&gt;That said, the point is there isn't a one-true-paradigm when it comes to abstracting design concepts. You can use t-shirt sizes, but maybe your team is happy using animals instead, or maybe it's preferred not to use variables at all.&lt;/p&gt;

&lt;p&gt;Find what works for you or your team, and if it happens to be a little creative, all the power to you!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://css-tricks.com/the-dilemma-of-naming-font-size-variables/"&gt;The Dilemma of Naming Font Size Variables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/codyhouse/create-your-design-system-part-1-typography-7c630d9092bd"&gt;Creating Your Design System&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bradfrost.com/blog/post/creating-themeable-design-systems/"&gt;Creating Themeable Design Systems&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>fun</category>
    </item>
    <item>
      <title>I can CSS a focused input, but what about its label?</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Fri, 04 Mar 2022 13:29:41 +0000</pubDate>
      <link>https://dev.to/auroratide/i-can-css-a-focused-input-but-what-about-its-label-2ob7</link>
      <guid>https://dev.to/auroratide/i-can-css-a-focused-input-but-what-about-its-label-2ob7</guid>
      <description>&lt;p&gt;Welcome to Stackazon, your one-stop shop for great solutions to tricky coding problems! Your search query, "&lt;strong&gt;How do I style a label when its input is focused?&lt;/strong&gt;", has returned five results.&lt;/p&gt;

&lt;p&gt;Our ratings for this query consider browser compatibility, accessibility, and complexity. Be sure to read our reviewers' opinions for additional resources and justification for the rating.&lt;/p&gt;

&lt;p&gt;The best part about Stackazon? Everything is free, and delivery is instant! No prime subscription needed either!&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; The people, ratings, and reviews are fictional and based on my opinion and knowledge of key factors. What solution is best always depends on context and your use case!&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;This is mostly my wacky way of demonstrating how to evaluate important factors when coding for the web 😊&lt;/small&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Problem&lt;/li&gt;
&lt;li&gt;
Solutions

&lt;ul&gt;
&lt;li&gt;
Using Adjacent Siblings (🌕🌕🌕🌗🌑)&lt;/li&gt;
&lt;li&gt;
Using Javascript (🌕🌕🌕🌘🌑)&lt;/li&gt;
&lt;li&gt;
Using :focus-within with Explicit Labels (🌕🌕🌕🌕🌘)&lt;/li&gt;
&lt;li&gt;
Using :focus-within with Implicit Labels (🌕🌕🌕🌕🌑)&lt;/li&gt;
&lt;li&gt;
Using :has (🌖🌑🌑🌑🌑)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Codepen&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
  &lt;small&gt;Why do you use moons instead of stars?&lt;/small&gt;
  &lt;p&gt;&lt;small&gt;Here at Stackazon, we rate using moons instead of stars because emoji sets support different moon phases, which can indicate fractional rating! Thank you, Moon, for having such convenient phases ❤️&lt;/small&gt;&lt;/p&gt; 


&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Most of the time, an &lt;a href="https://css-tricks.com/html-inputs-and-labels-a-love-story/"&gt;HTML input element should be properly labeled&lt;/a&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;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&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;But let's say you want to highlight the "Name" label if someone is typing stuff into its text field. As web developers, we can use CSS to customize how the input looks when focused:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&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;But... how do you do the same for the label? Turns out it's tricky!&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutions
&lt;/h2&gt;

&lt;p&gt;Our Stackazon reviewers reference the following resources (and we recommend that you do too when evaluating solutions for other issues!):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://caniuse.com/"&gt;Can I Use&lt;/a&gt; - Tracks the browser compatibility of various web features&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://a11ysupport.io/"&gt;Accessibility Support&lt;/a&gt; - Tracks to what degree assistive technologies implement accessibility specifications&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.w3.org/TR/WCAG21/"&gt;Web Content Accessibility Guidelines&lt;/a&gt; - Essentially a specification for maximizing web accessibility, also called WCAG
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/"&gt;MDN Web Docs&lt;/a&gt; - Curated documentation of web features including best practices (and recently got an upgrade!)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using Adjacent Siblings
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; 🌕🌕🌕🌗🌑&lt;/p&gt;

&lt;p&gt;CSS provides an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator"&gt;adjacent sibling combinator&lt;/a&gt; which lets you match an element that is &lt;em&gt;directly after&lt;/em&gt; another element.&lt;/p&gt;

&lt;p&gt;If you structure your HTML such that the label is &lt;em&gt;directly after&lt;/em&gt; the input:&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;class=&lt;/span&gt;&lt;span class="s"&gt;"input-container"&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;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can style the label with the adjacent sibling combinator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&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;However, for a text field, conventionally the label is supposed to come &lt;em&gt;before&lt;/em&gt; the input.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6hz8KEga--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v59qm6gnv05xvwdhgil4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6hz8KEga--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v59qm6gnv05xvwdhgil4.png" alt="A text input field is followed by a label, 'First Name'." width="880" height="248"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When the label comes after the text input field, it looks strange.&lt;/p&gt;



&lt;p&gt;Unfortunately, the fancy adjacent sibling plus sign only works top-to-bottom! If you try to use &lt;code&gt;label + input:focus&lt;/code&gt;, then the styles will only apply to the input directly and &lt;em&gt;not&lt;/em&gt; the label. If the label comes first in the markup, then you can't use this combinator to select the label when the input is focused.&lt;/p&gt;

&lt;p&gt;That said, CSS to the rescue again! CSS can visually reorder elements on the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.input-container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&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;h4&gt;
  
  
  Reviews
&lt;/h4&gt;

&lt;p&gt;Our reviewers gave this solution 3.5 out of 5 moons, citing excellent browser compatibility but with some accessibility concerns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ivan Eaton&lt;/strong&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Of the solutions presented, this has the best browser compatibility, as the adjacent sibling combinator has been implemented in all major browsers, included Internet Explorer, for many years.&lt;/p&gt;

&lt;p&gt;Flexbox, though newer, is also widely supported.&lt;/p&gt;

&lt;p&gt;See: &lt;a href="https://drafts.csswg.org/selectors/#adjacent-sibling-combinators"&gt;W3C Selectors Level 4&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Serena Redmon&lt;/strong&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am concerned about how &lt;strong&gt;&lt;a href="https://webaim.org/techniques/screenreader/"&gt;screen readers&lt;/a&gt;&lt;/strong&gt; announce the text field and its label. Visually, it looks like the label comes first since we used the &lt;code&gt;order&lt;/code&gt; property, but the screen reader announces the input first instead since it is first in the HTML code.&lt;/p&gt;

&lt;p&gt;The Web Content Accessibility Guidelines (WCAG) stipulate that &lt;q&gt;order of content in the source code [should be] the same as the visual presentation of the content&lt;/q&gt; in order to minimize confusion when using accessibility tools. Therefore, I've rated this solution lower as the adjacency combinator requires the elements be in unconventional order.&lt;/p&gt;

&lt;p&gt;See: &lt;a href="https://www.w3.org/TR/WCAG20-TECHS/C27.html"&gt;WCAG on Making the DOM order match the visual order&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Using Javascript
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; 🌕🌕🌕🌘🌑&lt;/p&gt;

&lt;p&gt;When an input is focused or unfocused, it emits an &lt;strong&gt;event&lt;/strong&gt; which we can listen to with Javascript. Additionally, the element has a reference to all of its labels via the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/labels"&gt;labels property&lt;/a&gt;. Therefore, we can leverage Javascript with the following strategy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When the input receives focus, add a &lt;code&gt;focused&lt;/code&gt; class to its label.&lt;/li&gt;
&lt;li&gt;When the input loses focus (called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/blur_event"&gt;blurring&lt;/a&gt;), remove the &lt;code&gt;focused&lt;/code&gt; class.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;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;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&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;input&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;focus&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="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="nx"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;label&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;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;focused&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;input&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;blur&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="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="nx"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;label&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;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;focused&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now with CSS, you just need to apply styles to the &lt;code&gt;focused&lt;/code&gt; class!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.focused&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&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;h4&gt;
  
  
  Reviews
&lt;/h4&gt;

&lt;p&gt;Our reviewers gave this solution 3.25 out of 5 moons, citing some browser compatibility issues and complexity as a result of using Javascript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ivan Eaton&lt;/strong&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The strategy of leveraging Javascript bypasses all the potential problems with browser compatibility for CSS features, but exchanges that for problems in Javascript feature support.&lt;/p&gt;

&lt;p&gt;More specifically, the &lt;code&gt;labels&lt;/code&gt; property with this solution uses is not supported in IE 11 and can result in errors if not handled. To maximize compatibility while still using this general approach, I recommend reading &lt;a href="https://stackoverflow.com/questions/285522/find-html-label-associated-with-a-given-input"&gt;how to find an input's associated label&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See: &lt;a href="https://caniuse.com/mdn-api_htmlinputelement_labels"&gt;Can I Use HTMLInputElement labels&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Jose Scott&lt;/strong&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Introducing Javascript when there are decent CSS-only solutions can feel like overkill. The Javascript here introduces the need to properly manage when and how listeners are added to inputs, which requires some care for sufficiently dynamic pages and forms.&lt;/p&gt;

&lt;p&gt;That said, this solution may be preferred if an input has many labels or the input and its label are far apart in the HTML hierarchy such that it is difficult to use CSS selectors to style them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Using :focus-within with Explicit Labels
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; 🌕🌕🌕🌕🌘&lt;/p&gt;

&lt;p&gt;CSS offers a relatively new pseudo-class called &lt;code&gt;:focus-within&lt;/code&gt; which matches an element if it &lt;em&gt;or any of its descendants&lt;/em&gt; have focus. Therefore, as long as the label and its input share a common parent element in HTML, we can use this to style the label:&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;class=&lt;/span&gt;&lt;span class="s"&gt;"input-container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"name-field"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name-field"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.input-container&lt;/span&gt;&lt;span class="nd"&gt;:focus-within&lt;/span&gt; &lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&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 works since the focused input is &lt;em&gt;within&lt;/em&gt; the &lt;code&gt;input-container&lt;/code&gt; div. The selector is essentially saying, "find an input container with focus somewhere inside of it, then find all the container's child labels."&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Of note, we are using the label's &lt;code&gt;for&lt;/code&gt; attribute to associate it to an input. If the input has an &lt;code&gt;id&lt;/code&gt; defined, setting &lt;code&gt;for&lt;/code&gt; to equal that id creates the relationship. Notice that in the HTML code above, both &lt;code&gt;for&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt; are "name-field". This is often called an explicit label.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;For more on explicit labels and their counterpart, implicit labels, read &lt;a href="https://www.w3.org/WAI/tutorials/forms/labels/"&gt;Labeling Controls&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Reviews
&lt;/h4&gt;

&lt;p&gt;Our reviewers gave this solution 4.25 out of 5 moons, citing lack of support in old browsers but having the best accessibility of solutions present.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ivan Eaton&lt;/strong&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Although a simple solution, &lt;code&gt;:focus-within&lt;/code&gt; is not supported in IE 11. In a world that is moving away from that old browser, this solution becomes better and better, but unfortunately I cannot recommend it to everyone.&lt;/p&gt;

&lt;p&gt;See: &lt;a href="https://caniuse.com/css-focus-within"&gt;Can I use :focus-within&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Serena Redmon&lt;/strong&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Of solutions presented, this supports accessibility tools the best: it properly assigns a label to an input and keeps code-order and visual-order the same, both being WCAG requirements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Using :focus-within with Implicit Labels
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; 🌕🌕🌕🌕🌑&lt;/p&gt;

&lt;p&gt;Instead of having a containing div, the label is able to contain its associated input directly.&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;label&amp;gt;&lt;/span&gt;Name
    &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="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this structure, the &lt;code&gt;:focus-within&lt;/code&gt; pseudo-class, which matches an element if it &lt;em&gt;or any of its descendants&lt;/em&gt; have focus, can be applied directly on the label. When the input inside of it has focus, then the label receives the styling we want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="nd"&gt;:focus-within&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&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;Associating a label and input via hierarchy like this, as opposed to using the input's &lt;code&gt;id&lt;/code&gt;, creates what's called an implicit label, in contrast to explicit labels in the other solutions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reviews
&lt;/h4&gt;

&lt;p&gt;Our reviewers gave this solution 4 out of 5 moons, citing minor accessibility issues and lack of support in old browsers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serena Redmon&lt;/strong&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Implicit labels are best used when the id of the input is not known and hence an explicit label cannot be created. This is because, generally, &lt;q&gt;explicit labels are better supported by assistive technology&lt;/q&gt; (Ref: &lt;a href="https://www.w3.org/WAI/tutorials/forms/labels/"&gt;Labeling Controls&lt;/a&gt;). That said, support has gotten better with time.&lt;/p&gt;

&lt;p&gt;For example, as of today, most screen readers now equally support implicit labels and explicit labels. However, &lt;strong&gt;&lt;a href="https://webaim.org/articles/motor/assistive#voicerecognition"&gt;voice control&lt;/a&gt;&lt;/strong&gt; software, which can be used by people with movement disabilities preventing them from using a keyboard or mouse, does not always adequately support implicit labels.&lt;/p&gt;

&lt;p&gt;See: &lt;a href="https://a11ysupport.io/tech/html/label_element"&gt;Accessibility Support for labels&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Ivan Eaton&lt;/strong&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Although a simple solution, &lt;code&gt;:focus-within&lt;/code&gt; is not supported in IE 11. In a world that is moving away from that old browser, this solution becomes better and better, but unfortunately I cannot recommend it to everyone.&lt;/p&gt;

&lt;p&gt;See: &lt;a href="https://caniuse.com/css-focus-within"&gt;Can I use :focus-within&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Using :has
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; 🌖🌑🌑🌑🌑&lt;/p&gt;

&lt;p&gt;A notorious fact about CSS is there is no way to style an element based on elements after it in HTML. So for example, you can't style a quote that contains a link differently than a quote that doesn't, and more relevantly you can't style a label whose input directly after it is focused.&lt;/p&gt;

&lt;p&gt;At least, that's true for now: Introducing the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:has"&gt;:has() pseudo-class&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;This pseudo-class matches the element if the selector provided as a parameter also matches. The inner selector is relative to the element with the &lt;code&gt;:has&lt;/code&gt; on it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="nd"&gt;:has&lt;/span&gt;&lt;span class="o"&gt;(+&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;red&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 says "select labels &lt;em&gt;that have&lt;/em&gt; an adjacent sibling which is a focused input". Unlike the Using Adjacent Siblings solution, this does not style the input. This styles the label, exactly what we want.&lt;/p&gt;

&lt;p&gt;What's neat about this solution is that the label gets to come before its input &lt;em&gt;and&lt;/em&gt; it doesn't require a containing div.&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;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Reviews
&lt;/h4&gt;

&lt;p&gt;Our reviewers gave this solution 0.75 out of 5 moons, citing its experimental status as rendering it unusable for now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ivan Eaton&lt;/strong&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Currently, nothing except the newest version of Safari supports this selector, making it impossible to use. Thankfully, Chrome has a &lt;a href="https://chromestatus.com/feature/5794378545102848"&gt;proposal&lt;/a&gt; out, so maybe someday in the future we'll see this added more universally!&lt;/p&gt;

&lt;p&gt;See: &lt;a href="https://caniuse.com/css-has"&gt;Can I Use :has&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Codepen
&lt;/h2&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/LYOMNov?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>html</category>
      <category>css</category>
      <category>a11y</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Server Side Rendering a Random Number wasn't easy</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Fri, 28 Jan 2022 14:33:11 +0000</pubDate>
      <link>https://dev.to/auroratide/server-side-rendering-a-random-number-wasnt-easy-1ci9</link>
      <guid>https://dev.to/auroratide/server-side-rendering-a-random-number-wasnt-easy-1ci9</guid>
      <description>&lt;p&gt;Have you ever tried rendering a random number with &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; before? Here's a rather quick implementation:&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;const&lt;/span&gt; &lt;span class="nx"&gt;n&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="nf"&gt;random&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;p&amp;gt;&lt;/span&gt;{n}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Seems like nothing can go wrong, right? It even works if you plug it into the &lt;a href="https://svelte.dev/repl/b7a6b10307254f83afc900661b980974?version=3.46.3" rel="noopener noreferrer"&gt;REPL&lt;/a&gt;. But as soon you plug it into &lt;a href="https://kit.svelte.dev/" rel="noopener noreferrer"&gt;SvelteKit&lt;/a&gt;, Svelte's website framework, oh dear what's happening?&lt;/p&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fauroratide.com%2Fassets%2Fposts%2Fserver-side-rendering-a-random-number%2Frefresh.webp" alt="When 'Reload' is clicked, two random numbers flash on the screen instead of one."&gt;&lt;p&gt;When the page is refreshed, a number shows briefly before being replaced&lt;/p&gt;
  


&lt;p&gt;The footage here is slowed down, but for some reason &lt;em&gt;two&lt;/em&gt; random numbers get shown when the page loads, the second one rapidly replacing the first 😥. What's going on, and how do we fix this?&lt;/p&gt;

&lt;p&gt;
  &lt;small&gt;A similar issue occurs when using &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;NextJS&lt;/a&gt;.&lt;/small&gt;
  &lt;p&gt;&lt;small&gt;You won't get two flashing numbers. Instead, the console displays a nasty red error stating, "Warning: Text content did not match." This is definitely better since the site visitor won't see that, but it's still an issue, and it can lead to further problems if not addressed.&lt;/small&gt;&lt;/p&gt; 



&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I want to understand the problem.&lt;/li&gt;
&lt;li&gt;Take me to the solution!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Where do the numbers come from?
&lt;/h2&gt;

&lt;p&gt;Essentially, the random number is being generated twice: once on the &lt;strong&gt;server&lt;/strong&gt;, and once on the &lt;strong&gt;client&lt;/strong&gt; computer. This is because some frontend frameworks, SvelteKit included, practice something called server-side rendering (SSR):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The server runs the framework's Javascript code to generate nice juicy HTML, and the result is sent to the browser to render.&lt;/li&gt;
&lt;li&gt;The browser renders the result, and begins downloading the Javascript code.&lt;/li&gt;
&lt;li&gt;Once downloaded, the framework &lt;strong&gt;hydrates&lt;/strong&gt; the existing HTML with the Javascript, making the page interactive.&lt;/li&gt;
&lt;/ol&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmea8opu0tlrqsfzywe8n.png" alt="Step 1: JS on server becomes HTML; Step 2: HTML goes to client; Step 3: JS hydrates on client"&gt;&lt;p&gt;Flow diagram illustrating server-side rendering&lt;/p&gt;
  

&lt;h3&gt;
  
  
  Hydration
&lt;/h3&gt;

&lt;p&gt;The hydration step is key to understanding the problem with randomness.&lt;/p&gt;

&lt;p&gt;Imagine for a moment that you just purchased a new flashlight. Dang, it sure is nice that you don't have to build one yourself! Unfortunately, the flashlight does not come with batteries, so you have to install those before you can light up your day. To help you out, the shipment provides instructions on where the batteries should go:&lt;/p&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72kt0ets4xqd5qom2w9s.png" alt="A flashlight on the left contrasted with a different kind of flashlight on the right, the right demonstrating where the battery goes"&gt;&lt;p&gt;What you got does not match the provided instructions&lt;/p&gt;
  


&lt;p&gt;What gives?! The instructions don't match the flashlight, so where am I supposed to put the batteries? How do I &lt;strong&gt;hydrate&lt;/strong&gt; my flashlight?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;/analogy&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When HTML is rendered server-side, it is not yet interactive; it only becomes interactive once Javascript has been applied. The process of applying interaction to server-rendered content is called hydration, and it relies on one key assumption:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The results of rendering on the server and the client should match.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In our flashlight analogy, when the instructions don't match the product, we get confused. Similarly, if client-side Svelte expects there to be a button on which to attach an event, and the server failed to render that button, then Svelte has to make a decision.&lt;/p&gt;

&lt;p&gt;In the case of our random number, Svelte decides to replace whatever's there with what it &lt;em&gt;thinks&lt;/em&gt; should be there. Since hydration takes time to do, we get a flash of two numbers.&lt;/p&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpkzl66yngju7kuvr6sn.png" alt="Step 1: JS on server converts a random number 2 into HTML; Step 2: HTML goes to client; Step 3: JS on client replaces HTML with a newly random number 7"&gt;&lt;p&gt;How the random number scenario results from SSR&lt;/p&gt;
  

&lt;h2&gt;
  
  
  Ensuring the same random numbers
&lt;/h2&gt;

&lt;p&gt;If the problem is that the server and client are generating different numbers, then we need a way for them to generate the same numbers instead. In other words:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The server must send enough info for the client to generate the same numbers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In particular, we can take advantage of the fact that random number generators are not actually random. In fact, they are &lt;em&gt;pseudo&lt;/em&gt;-random, relying on well-defined algorithms to generate a pattern that is so chaotic that it's generally good enough.&lt;/p&gt;

&lt;p&gt;Many such pseudo-random number generators take a &lt;strong&gt;seed&lt;/strong&gt; as an input and use that seed to deterministically create an entire sequence of numbers. The key insight is that using the same seed always results in the same sequence of numbers.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Imagine if by saying a word out loud like "apple", you could cause your dice to always roll the numbers 4, 6, 3, 1, 6... in that order, every time. Seeding a random number generator is like that, and each seed produces a different sequence of numbers.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;So step by step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The server generates a single &lt;strong&gt;random seed&lt;/strong&gt; and uses that to generate HTML&lt;/li&gt;
&lt;li&gt;That seed is sent to the client along with the HTML&lt;/li&gt;
&lt;li&gt;The client initializes its own random number generator with the seed, ensuring the exact same sequence of random numbers are generated&lt;/li&gt;
&lt;li&gt;💰💰💰&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 2 differs in implementation from framework to framework, but let's see an example in SvelteKit (since that's what I was using when I ran into this issue).&lt;/p&gt;
&lt;h3&gt;
  
  
  A SvelteKit Example
&lt;/h3&gt;

&lt;p&gt;In order to send the seed to the client consistently, we can rely on one of the properties of SvelteKit's &lt;a href="https://kit.svelte.dev/docs#loading-input-fetch" rel="noopener noreferrer"&gt;special &lt;code&gt;fetch&lt;/code&gt; function&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It makes a copy of the response when you use it, and then sends it embedded in the initial page load for hydration&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, when Svelte makes a &lt;code&gt;fetch&lt;/code&gt; on the server, rather than forcing the client to do the same &lt;code&gt;fetch&lt;/code&gt;, it caches the result and sends it to the client, saving a lot of time.&lt;/p&gt;

&lt;p&gt;Which means, if we have an endpoint that generates a random seed, we can guarantee the client sees the same seed!&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Even though this example is for SvelteKit, a similar context-based strategy can be used with React's NextJS, except it's perhaps easier since an endpoint does not need to be set up.&lt;/small&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Endpoint for a random seed
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// random-seeds.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &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="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// use your favorite algorithm for this&lt;/span&gt;
    &lt;span class="na"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;generateRandomString&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;h4&gt;
  
  
  2. Get the seed in a layout
&lt;/h4&gt;

&lt;p&gt;We want the seed to be available on all pages, so we can fetch it within the primary &lt;a href="https://kit.svelte.dev/docs#layouts" rel="noopener noreferrer"&gt;layout&lt;/a&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="c"&gt;&amp;lt;!-- __layout.svelte --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;context=&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;load&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;fetch&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;// fetch's result will be cached for the client&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/random-seeds&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;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&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 shouldn't break the app&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;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;seed&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;small&gt;You'll notice a &lt;code&gt;catch&lt;/code&gt; is used to ensure that any possible failure that might occur doesn't result in a crash. Proper error handling is always important to remember!&lt;/small&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Create a seedable random number generator
&lt;/h4&gt;

&lt;p&gt;Interestingly, Javascript's native &lt;code&gt;random()&lt;/code&gt; function cannot be seeded. Therefore, we have to find or roll out our own random number generator which &lt;em&gt;can&lt;/em&gt; be seeded.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.npmjs.com/package/seedrandom" rel="noopener noreferrer"&gt;seedrandom&lt;/a&gt; library by David Bau is very good for this, or if you want more control over what's bundled, feel free to choose from this &lt;a href="https://github.com/bryc/code/blob/master/jshash/PRNGs.md" rel="noopener noreferrer"&gt;list of pseudorandom number generators&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="c1"&gt;// lib/random.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;seedrandom&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;seedrandom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seeded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seed&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;seedrandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seed&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;const&lt;/span&gt; &lt;span class="nx"&gt;usingMath&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="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  4. Create a context for the generator to live in
&lt;/h4&gt;

&lt;p&gt;We want the random number generator to be available everywhere in the app that it's needed without having to send it several layers deep via props. Svelte's &lt;a href="https://svelte.dev/tutorial/context-api" rel="noopener noreferrer"&gt;context api&lt;/a&gt; is very useful here, since the &lt;code&gt;__layout.svelte&lt;/code&gt; is the root of every page.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// also lib/random.js&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;getContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setContext&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="s1"&gt;svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Symbol&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;const&lt;/span&gt; &lt;span class="nx"&gt;generator&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="nf"&gt;getContext&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="nf"&gt;usingMath&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;const&lt;/span&gt; &lt;span class="nx"&gt;setGenerator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generator&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;setContext&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;generator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  5. Initialize the generator in layout
&lt;/h4&gt;

&lt;p&gt;We can now initialize the generator in the layout where we had previously fetched the seed to use.&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;!-- __layout.svelte --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&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;setGenerator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;seeded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;usingMath&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="s1"&gt;$lib/random&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;

  &lt;span class="nf"&gt;setGenerator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;seeded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;usingMath&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;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  6. Invoke the generator to get a consistent number!
&lt;/h4&gt;

&lt;p&gt;And &lt;em&gt;finally&lt;/em&gt;, we can use all this infrastructure to get a random number that is the same on both the server and client!&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;!-- index.svelte --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&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;nextRandom&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="s1"&gt;$lib/random&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;nextRandom&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;p&amp;gt;&lt;/span&gt;{n}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Some Considerations
&lt;/h3&gt;

&lt;p&gt;The approach I took above was perfect for my use case in which the random numbers were used solely for aesthetics. If, however, you need random numbers for something security-related, definitely double check whether this approach fits within your constraints!&lt;/p&gt;

&lt;p&gt;Additionally, the solution presented here works iff the server and client generate content &lt;em&gt;in the same order&lt;/em&gt;. You could imagine that if the client built the page backward, the same sequence of random numbers would be generated but they'd be applied to different pieces of the page. I'm not sure why this would happen, but if this is a significant factor for you, then it requires a more nuanced approach.&lt;/p&gt;



&lt;p&gt;Here are a few other important factors to consider as brought up by comments below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Size&lt;/strong&gt;: A great goal is to send as little to the client as possible, and a random number generator has non-zero size. Remember, the principle is for the server to "send enough info", and so a great alternative approach is just to send all the generated numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: If we generate the numbers on the server and then again on the client, we're doing the same thing twice. For small counts of random numbers this is ok, but for large counts it can't be ignored!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where it is important, be sure to consider the possible ups and downs of different approaches.&lt;/p&gt;
&lt;h3&gt;
  
  
  Github Repo
&lt;/h3&gt;

&lt;p&gt;As usual, here's a repo to explore the raw solution. Hopefully it is helpful!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Auroratide" rel="noopener noreferrer"&gt;
        Auroratide
      &lt;/a&gt; / &lt;a href="https://github.com/Auroratide/sveltekit-ssr-with-randomness" rel="noopener noreferrer"&gt;
        sveltekit-ssr-with-randomness
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you are using a framework with server-side rendering, thoroughly examine and test places where it is possible for the server and client results to differ, such as with random numbers or login state.&lt;/li&gt;
&lt;li&gt;Where consistency is desired, the server must send enough info for the client to replicate the results exactly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And a bonus tip:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you get stuck, ask for help! I was scratching my head for a while before asking the folks at &lt;a href="https://stackoverflow.com/questions/70714461/sveltekit-rendering-a-random-prop-is-different-between-server-and-client/70776238" rel="noopener noreferrer"&gt;Stack Overflow&lt;/a&gt;, and as a result I learned something new about how SvelteKit works.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>svelte</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>What HTML tag do you use for Sarcasm?</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Tue, 12 Oct 2021 16:00:32 +0000</pubDate>
      <link>https://dev.to/auroratide/what-html-tag-do-you-use-for-sarcasm-48he</link>
      <guid>https://dev.to/auroratide/what-html-tag-do-you-use-for-sarcasm-48he</guid>
      <description>&lt;p&gt;Ah yes, sarcasm, the &lt;em&gt;pinnacle&lt;/em&gt; of human language. Life would be so &lt;em&gt;incredibly&lt;/em&gt; dull without it.&lt;/p&gt;

&lt;p&gt;And yet, despite sarcasm's profound influence on both oral and written conversation, we don't have a way to denote it in text! I mean, at least in person you can roll your eyes or change your tone to indicate some witty derision. But text? It's just neutral words on a page. We can't even use code to properly mark something as sarcastic!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Or &lt;em&gt;can&lt;/em&gt; we?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can't we use punctuation⸮&lt;/li&gt;
&lt;li&gt;Beyond the period 🧐&lt;/li&gt;
&lt;li&gt;Huh, textual punctuation? &amp;lt;/sarcasm&amp;gt;&lt;/li&gt;
&lt;li&gt;&amp;lt;/sarcasm&amp;gt; is official?!&lt;/li&gt;
&lt;li&gt;HTML Tags are like Knives&lt;/li&gt;
&lt;li&gt;
Tagging Sarcasm with HTML

&lt;ul&gt;
&lt;li&gt;The... &amp;lt;i&amp;gt; Tag?&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Em&lt;/em&gt;ulating Verbal Cues&lt;/li&gt;
&lt;li&gt;But don't use &amp;lt;q&amp;gt;!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Sooo... where does this leave us?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Can't we use punctuation⸮
&lt;/h2&gt;

&lt;p&gt;Do you enjoy lemonade on a hot summer day. I know I sure do?&lt;/p&gt;

&lt;p&gt;...Is it just me, or is something &lt;em&gt;off&lt;/em&gt; about those two sentences⸮&lt;/p&gt;

&lt;p&gt;Sorry, that was meant to be a rhetorical question! You could tell because I used the &lt;b&gt;percontation point&lt;/b&gt;, that backwards question mark thing. It was invented in the 1500s specifically for questions not meant to be answered. You don't really see it &lt;del&gt;a lot&lt;/del&gt; ever nowadays though, as it fell out of favor a long time ago.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fby9b6rlfoacma6qhlf7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fby9b6rlfoacma6qhlf7a.png" alt="A backwards question mark" width="800" height="187"&gt;&lt;/a&gt;&lt;p&gt;The Percontation Point sure looks funky.&lt;/p&gt;&lt;/p&gt;

&lt;p&gt;Anyways, those first couple sentences feel wrong because I used unexpected punctuation. In a way, our periods, exclamation points, and question marks convey &lt;em&gt;tone&lt;/em&gt;, namely a neutral, excited, and questioning tone respectively.&lt;/p&gt;

&lt;p&gt;So if punctuation makes words sound exciting, how about punctuation for making something sound sarcastic?&lt;/p&gt;

&lt;p&gt;And people have tried that! Let me introduce you to...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fefbyohr3ytxophafcsj2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fefbyohr3ytxophafcsj2.png" alt="Four punctuation points in a row." width="800" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The point d'ironie (1899)&lt;/li&gt;
&lt;li&gt;The irony point (1966)&lt;/li&gt;
&lt;li&gt;The ironieteken (2007)&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://www.sarcmark.com/"&gt;SarkMark&lt;/a&gt;&lt;sup&gt;TM&lt;/sup&gt; (2010, and yes... it's even trademarked)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And of course, none of these ever caught on. Looks like we're stuck with just three ways to end a sentence, &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, or &lt;code&gt;!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Except...&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqy9vtnyybfc9j2qkyk8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqy9vtnyybfc9j2qkyk8p.png" alt="What if I told you we have hundreds of punctuation marks?" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond the period 🧐
&lt;/h2&gt;

&lt;p&gt;The web has inspired written (typed?) language to adapt in fascinating ways, not the least of which is the advent of &lt;strong&gt;emoji&lt;/strong&gt;. Text loses facial cues, so... let's just add faces to text!&lt;/p&gt;

&lt;p&gt;End a sentence with an emoji and suddenly the words have a voice 😊&lt;/p&gt;

&lt;p&gt;Let's see how emoji changes one simple sentence...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;That was a good joke 🤣&lt;/li&gt;
&lt;li&gt;That was a good joke 👏&lt;/li&gt;
&lt;li&gt;That was a good joke 🙃&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first two seem sincere in their praise, albeit in different ways. That last one, though, sounds a bit... &lt;em&gt;sarcastic&lt;/em&gt; 🤔&lt;/p&gt;

&lt;p&gt;So in a way, emoji used this way can be thought of &lt;em&gt;like&lt;/em&gt; punctuation, giving sentences a very wide variety of tones you'd otherwise only be able to pick up in person.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmgig4lnonyf87rtc558.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmgig4lnonyf87rtc558.png" alt="" width="800" height="74"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But maybe a yellow face isn't appropriate or possible where you want to make your snide comment. Is there a way to use &lt;em&gt;just text&lt;/em&gt; as punctuation?&lt;/p&gt;

&lt;h2&gt;
  
  
  Huh, textual punctuation? &amp;lt;/sarcasm&amp;gt;
&lt;/h2&gt;

&lt;p&gt;Using text as punctuation may sound a bit silly at first, but people have (and still do) actually do this for sarcasm! Peruse the internet long enough and you might have seen people write sentences like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;John Doe is a brilliant politician &amp;lt;/sarcasm&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That &lt;a href="https://www.urbandictionary.com/define.php?term=%3C%2Fsarcasm%3E"&gt;&amp;lt;/sarcasm&amp;gt;&lt;/a&gt; bit denotes sarcasm (clearly). And yes, I &lt;em&gt;did&lt;/em&gt; just link Urban Dictionary as a reference &amp;lt;/sarcasm&amp;gt;.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Nowadays, it's usually shortened to just &lt;code&gt;/s&lt;/code&gt;.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;So where did such a funny looking thing come from anyway?&lt;/p&gt;

&lt;p&gt;Well, it turns out to be a bit of a &lt;strong&gt;code joke&lt;/strong&gt;! Websites are coded (in part) using a language called Hypertext Markup Language (HTML). HTML gives pages structure, determining whether a block of text is a paragraph, or a heading, or some other thing. This is done using &lt;b&gt;tags&lt;/b&gt;; for example, the bolded "code joke" from the earlier sentence uses the &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt; tag, which indicates it is an &lt;em&gt;important&lt;/em&gt; phrase.&lt;/p&gt;

&lt;p&gt;A web author would code it 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;It is a &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;code joke&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every start tag is paired with an end tag, so the &lt;code&gt;&amp;lt;/strong&amp;gt;&lt;/code&gt; there indicates the end of the important text. &lt;/p&gt;

&lt;p&gt;And while &lt;code&gt;&amp;lt;sarcasm&amp;gt;&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; a real HTML tag, people started using "&amp;lt;/sarcasm&amp;gt;" to indicate the end of a sarcastic phrase!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Wait wait wait&lt;/em&gt;, did I say it wasn't a real tag? Let me correct myself real quick...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5nsm37wxx5qqjocj2aj6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5nsm37wxx5qqjocj2aj6.gif" alt="A man quickly flips through a book." width="640" height="360"&gt;&lt;/a&gt;&lt;p&gt;&lt;a href="https://tenor.com/view/book-confusion-huh-what-read-gif-16432979"&gt;Book Confusion&lt;/a&gt; by &lt;a href="https://tenor.com"&gt;tenor.com&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &amp;lt;/sarcasm&amp;gt; is official?!
&lt;/h2&gt;

&lt;p&gt;Funnily enough, &lt;code&gt;&amp;lt;/sarcasm&amp;gt;&lt;/code&gt; is in the &lt;em&gt;&lt;a href="https://html.spec.whatwg.org"&gt;official HTML rulebook&lt;/a&gt;&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;All the way down in &lt;a href="https://html.spec.whatwg.org/#parsing-main-inbody"&gt;section 13.2.6.4.7&lt;/a&gt; is a little blurb telling browsers what to do if they encounter &lt;code&gt;&amp;lt;/sarcasm&amp;gt;&lt;/code&gt; in code:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[When handling a token with] An end tag whose tag name is "sarcasm": Take a deep breath, then act as described in the "any other end tag" entry below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ironically, the instruction itself is rather sarcastic. But perhaps disappointingly, this is saying there's nothing special about the sarcasm end tag, and it should be treated like everything else. In other words, it's just a jab at the historical use of the meme.&lt;/p&gt;

&lt;p&gt;And besides, this just the &lt;em&gt;end&lt;/em&gt; tag; the handbook has nothing for a start tag &lt;code&gt;&amp;lt;sarcasm&amp;gt;&lt;/code&gt;, and every &lt;em&gt;real&lt;/em&gt; HTML element has a start tag.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvg1rmeombu34r5igzbzs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvg1rmeombu34r5igzbzs.png" alt="" width="800" height="65"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hmm, speaking of &lt;em&gt;real&lt;/em&gt; HTML elements... above we saw that &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt; was used to mark text as being very important, and yet it wasn't &lt;em&gt;named&lt;/em&gt; &lt;code&gt;&amp;lt;important&amp;gt;&lt;/code&gt;. So, even if there's not an HTML element &lt;em&gt;named&lt;/em&gt; &lt;code&gt;&amp;lt;sarcasm&amp;gt;&lt;/code&gt;, is it possible for there to be something we could &lt;em&gt;use&lt;/em&gt; for sarcasm?&lt;/p&gt;

&lt;p&gt;In other words, &lt;strong&gt;is there a way to denote sarcasm... with code?!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  HTML Tags are like Knives
&lt;/h2&gt;

&lt;p&gt;Did you know that some knives have holes in them?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgq0i9x90wtkyvtww4hz9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgq0i9x90wtkyvtww4hz9.png" alt="A knife with three large holes on the blade." width="800" height="410"&gt;&lt;/a&gt;&lt;p&gt;A &lt;a href="https://www.cutco.com/products/product.jsp?item=traditional-cheese-knife"&gt;Cutco Cheese Knife&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;

&lt;p&gt;Those holes aren't there to be trendy. It turns out a knife like this is designed specifically for cutting &lt;em&gt;cheese&lt;/em&gt;. I dunno if you're like me and just cut cheese with a normal knife, but sometimes when I do that the cheese sticks to the blade. The holes on a cheese knife prevent that stickage, allowing for a cleaner, far more exquisite cut.&lt;/p&gt;

&lt;p&gt;Indeed, cooking is an advanced enough field that it has a specific knife for practically any conceivable purpose...&lt;/p&gt;

&lt;p&gt;...kinda like HTML tags! The &lt;a href="https://html.spec.whatwg.org"&gt;official HTML rulebook&lt;/a&gt; lists a myriad of tags, each with a specific purpose in mind.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7dfcc7dyhhu4pv2f94bo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7dfcc7dyhhu4pv2f94bo.png" alt="" width="800" height="66"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See, HTML tags impart meaning, or &lt;strong&gt;semantics&lt;/strong&gt;, to text they annotate. Here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt; indicates that the text is important, serious, or urgent.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt; is used for text that is a direct quote from somewhere else.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; denotes the main title of the web page. As a side effect, it also usually makes the title visibly larger.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because each tag has specific semantics, it's possible to misuse them. Just as how I shouldn't use a butter knife to cut boned meat, a web author would not use an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tag just to make some text big. The &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; tag is &lt;em&gt;only&lt;/em&gt; for the page's title, so to make some different text big the author would need to use something else.&lt;/p&gt;

&lt;p&gt;So our question, really, is whether or not the glorious HTML handbook has a tag whose semantics include sarcasm!&lt;/p&gt;

&lt;p&gt;
  &lt;small&gt;Why would we want this anyway?&lt;/small&gt;
  &lt;p&gt;&lt;small&gt;&lt;a href="https://users.soe.ucsc.edu/~maw/papers/kbs_2014_justo.pdf"&gt;Studies with computers&lt;/a&gt; have shown that machines are not great at identifying sarcasm without significant help. Using code to annotate things like importance, emphasis, and sarcasm can help machines.&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;One practical use is with screen readers, which read web pages aloud to those who cannot see the page. Maybe there's a future where if text is marked as sarcastic, the screen reader can indicate as much by fluctuating its tone.&lt;/small&gt;&lt;/p&gt; 


&lt;/p&gt;
&lt;h2&gt;
  
  
  Tagging Sarcasm with HTML
&lt;/h2&gt;

&lt;p&gt;Let's say your friend told a pretty bad pun, and somehow your able to respond with HTML code. You want to say, "That was perfect." Problem is, that phrase on its own is very ambiguous. If only you could mark it somehow...&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;SOMETHING&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;That was perfect.&lt;span class="nt"&gt;&amp;lt;/SOMETHING&lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The... &amp;lt;i&amp;gt; Tag?
&lt;/h3&gt;

&lt;p&gt;Well, there are dozens upon dozens of HTML tags, and &lt;em&gt;none&lt;/em&gt; of them are specifically for sarcasm. How perfect 🙃&lt;/p&gt;

&lt;p&gt;The one tag that comes the closest is the &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag. It has many uses, one of them being used for text that is in an &lt;q&gt;alternate voice or mood&lt;/q&gt;. In a way, sarcasm &lt;em&gt;is&lt;/em&gt; a different mood from the rest of the text, so lacking an alternative...&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;i&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sarcasm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;That was perfect.&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;small&gt;It is recommended to use &lt;code&gt;class&lt;/code&gt; to specify why the &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag is being used, since the tag can be used for many different things.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;There's one &lt;strong&gt;very big problem&lt;/strong&gt; with this idea, though.&lt;/p&gt;

&lt;p&gt;By default, the &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag &lt;em&gt;italicizes&lt;/em&gt; text, and by convention, italic text is interpretted as verbal stress, not sarcasm. It is possible to undo the italics with Cascading Style Sheets (CSS), a web technology that lets authors adjust how things look. But doing that leaves us back at the beginning: "That was perfect," with no indication of sarcasm!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvstu0xzskb2zjgwyzaqc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvstu0xzskb2zjgwyzaqc.gif" alt="A man dramatically rolls his eyes." width="220" height="118"&gt;&lt;/a&gt;&lt;p&gt;&lt;a href="https://tenor.com/view/house-md-gregory-house-ugh-whatever-eye-roll-gif-7380271"&gt;Gregory House&lt;/a&gt; by &lt;a href="https://tenor.com"&gt;tenor.com&lt;/a&gt;&lt;/p&gt;&lt;/p&gt;

&lt;p&gt;Even though the text is &lt;em&gt;semantically&lt;/em&gt; tagged as being sarcastic, it does not outwardly present itself that way, which is arguably &lt;em&gt;less&lt;/em&gt; than useless. If only there were &lt;em&gt;some&lt;/em&gt; other way to make something appear sarcastic...&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Textual semantics is usually tied with conversations about &lt;b&gt;accessibility&lt;/b&gt;, making pages work for abled and disabled people alike. By adding semantics to a page, it becomes more usable by people who cannot otherwise see the page.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Thing is, accessibility goes both ways. If a screen reader announces text as a title to a non-sighted person, then that text better &lt;em&gt;appear&lt;/em&gt; like a title to sighted people as well!&lt;/small&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Em&lt;/em&gt;ulating Verbal Cues
&lt;/h3&gt;

&lt;p&gt;Sarcasm gets lost in text due to losing certain cues, like body language and tone. We saw that emoji are kind of able to simulate facial language, so is there a way to simulate &lt;em&gt;tone&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;In fact, there &lt;em&gt;is&lt;/em&gt;, and I've been using it all throughout this post!&lt;/p&gt;

&lt;p&gt;All of the &lt;strong&gt;&lt;em&gt;italic text&lt;/em&gt;&lt;/strong&gt; hints at some kind of verbal stress. In HTML code, this is accomplished using the &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt; tag, and according to the rulebook, its purpose is to &lt;em&gt;em&lt;/em&gt;phasize words and phrases in order to change the overall meaning of the sentence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;This &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;emphasizes&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&lt;/span&gt; the word.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, the following two sentences are exactly the same, but because a different word is emphasized in each, they imply different situations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"I did not eat the &lt;em&gt;cookie&lt;/em&gt;." - implying something else was eaten&lt;/li&gt;
&lt;li&gt;"I did not &lt;em&gt;eat&lt;/em&gt; the cookie." - implying something else happened to the cookie&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjzvzzx8s186f52e4iz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjzvzzx8s186f52e4iz1.png" alt="" width="800" height="51"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So let's get back to our "That was perfect" phrase. Now equipped with the glorious power of &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt;, we can do two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add &lt;em&gt;word cues&lt;/em&gt;, extra words that suggest a deeper meaning&lt;/li&gt;
&lt;li&gt;Add &lt;em&gt;verbal stress&lt;/em&gt; to sharpen the phrase's sarcasm&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
    &lt;p&gt;Wow, &lt;em&gt;that&lt;/em&gt; was &lt;em&gt;just&lt;/em&gt; perfect.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;Wow, &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;that&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&lt;/span&gt; was &lt;span class="nt"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;just&lt;span class="nt"&gt;&amp;lt;/em&amp;gt;&lt;/span&gt; perfect.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;
  &lt;small&gt;Can't I use &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; instead of &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt; for italics?&lt;/small&gt;
  &lt;p&gt;&lt;small&gt;&lt;strong&gt;No!&lt;/strong&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Even though both tags result in italic text, they have different purposes. The &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag is for an alternate mood, which is why it is appropriate to use to tag an entire sentence as generally sarcastic. The &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt; tag is used for verbal emphasis, which is why it is better for modifying key words to simulate speaking a phrase sarcastically.&lt;/small&gt;&lt;/p&gt; 

&lt;/p&gt;

&lt;h3&gt;
  
  
  But don't use &amp;lt;q&amp;gt;!
&lt;/h3&gt;

&lt;p&gt;There's one last HTML element worth talking about: &lt;code&gt;&amp;lt;q&amp;gt;&lt;/code&gt;! It represents text that is &lt;q&gt;quoted from another source&lt;/q&gt;, and has the effect of automatically adding quotation marks.&lt;/p&gt;

&lt;p&gt;Sarcasm is often associated with so-called "air quotes", but the &lt;code&gt;&amp;lt;q&amp;gt;&lt;/code&gt; element is &lt;em&gt;only&lt;/em&gt; for quoting some other thing. In fact, the HTML handbook goes so far to say &lt;q&gt;it is inappropriate to use the q element for marking up sarcastic statements&lt;/q&gt;!&lt;/p&gt;

&lt;p&gt;So yeah, don't use it 🙃&lt;/p&gt;

&lt;h2&gt;
  
  
  Sooo... where does this leave us?
&lt;/h2&gt;

&lt;p&gt;Text loses both verbal and non-verbal cues, making it harder to detect sarcasm. Oh no!&lt;/p&gt;

&lt;p&gt;But when there's a will, there's a way!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recreate facial cues with emoji 🙃&lt;/li&gt;
&lt;li&gt;Wittily use textual convention to your advantage &amp;lt;/sarcasm&amp;gt;&lt;/li&gt;
&lt;li&gt;In HTML code, tag a sentence as sarcastic with the &lt;code&gt;&amp;lt;i&amp;gt;&lt;/code&gt; tag.&lt;/li&gt;
&lt;li&gt;Or, strategically stress words with italics and &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So thousands of words later, I guess I should end by asking one last question.&lt;/p&gt;

&lt;p&gt;Was this ever &lt;em&gt;really&lt;/em&gt; a problem to begin with⸮&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.quickanddirtytips.com/education/grammar/how-to-show-sarcasm-in-text"&gt;How to show sarcasm in text&lt;/a&gt; - Sarah Peters&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Irony_punctuation"&gt;Irony Punctuation&lt;/a&gt; - Wikipedia&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://web-docs.stern.nyu.edu/pa/kruger_email_ego.pdf"&gt;Egocentrism Over E-Mail&lt;/a&gt; - Kruger et al&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://users.soe.ucsc.edu/~maw/papers/kbs_2014_justo.pdf"&gt;Extracting relevant knowledge for the detection of sarcasm&lt;/a&gt; - Justo et al&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://html.spec.whatwg.org"&gt;HTML Living Standard&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://html.spec.whatwg.org/#the-i-element"&gt;The i element&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://html.spec.whatwg.org/#the-em-element"&gt;The em element&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://html.spec.whatwg.org/#the-q-element"&gt;The q element&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>html</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Making a Toggle Switch into a New HTML Element</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Sat, 25 Sep 2021 01:40:05 +0000</pubDate>
      <link>https://dev.to/auroratide/making-a-toggle-switch-into-a-new-html-element-425c</link>
      <guid>https://dev.to/auroratide/making-a-toggle-switch-into-a-new-html-element-425c</guid>
      <description>&lt;p&gt;Hey, let's build a light bulb!&lt;/p&gt;

&lt;p&gt;Or, at least the on/off switch part of the light bulb... The &lt;strong&gt;toggle switch&lt;/strong&gt; is a super common user interface element to indicate whether some feature is active or not.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/JjJBKrW?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Switches like these are in fact so common, it would sure be nice if they were their own HTML 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;label&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Lightbulb&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Well, through the magic of &lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" rel="noopener noreferrer"&gt;web components&lt;/a&gt;&lt;/strong&gt;, it's actually possible to make this!&lt;/p&gt;

&lt;p&gt;My goal is to illustrate one way how to both &lt;strong&gt;build&lt;/strong&gt; and &lt;strong&gt;test&lt;/strong&gt; a web component. However, instead of going step-by-step "here's the code for making a toggle switch," we're gonna acutally (in some sense) assemble a light bulb representing the &lt;strong&gt;key aspects to building a reusable web component&lt;/strong&gt;, which apply when creating &lt;em&gt;any&lt;/em&gt; reusable element.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r2nq00x9t96i6id2tto.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r2nq00x9t96i6id2tto.png" alt="Light bulb, with parts represented by accessibility, attributes, javascript, events, and styling."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we assemble this light bulb piece by piece, we will also be making the &lt;code&gt;toggle-switch&lt;/code&gt; component we know and love!&lt;/p&gt;

&lt;p&gt;So all that said, let's build a light bulb!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Inventing a Light Bulb

&lt;ul&gt;
&lt;li&gt;Semantics: The Schematic&lt;/li&gt;
&lt;li&gt;Accessibility: The Cap&lt;/li&gt;
&lt;li&gt;Attributes: The Contact Wires&lt;/li&gt;
&lt;li&gt;Javascript: The Filament&lt;/li&gt;
&lt;li&gt;Events: The Inert Gas&lt;/li&gt;
&lt;li&gt;Styling: The Globe&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Summary&lt;/li&gt;
&lt;li&gt;Full Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;small&gt;For the code bits, I will be assuming some familiarity with the following:&lt;/small&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;small&gt;HTML, CSS, and Javascript (see &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web" rel="noopener noreferrer"&gt;Getting Started with the Web&lt;/a&gt;)&lt;/small&gt;&lt;/li&gt;
&lt;li&gt;&lt;small&gt;Using &lt;a href="https://docs.npmjs.com/about-npm" rel="noopener noreferrer"&gt;npm&lt;/a&gt; to install dependencies (see &lt;a href="https://nodesource.com/blog/an-absolute-beginners-guide-to-using-npm/" rel="noopener noreferrer"&gt;Beginner's Guide to Using npm&lt;/a&gt;)&lt;/small&gt;&lt;/li&gt;
&lt;li&gt;&lt;small&gt;Testing code with code (see &lt;a href="https://www.freecodecamp.org/news/how-to-start-unit-testing-javascript/" rel="noopener noreferrer"&gt;How to start unit testing&lt;/a&gt;)&lt;/small&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Here's a bit of a tl;dr showing all the big points to think about when creating web components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Components create &lt;strong&gt;new semantics&lt;/strong&gt; through custom elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessible&lt;/strong&gt; components allow for multiple methods of interaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attributes&lt;/strong&gt; surface important state, configuration, and nuanced meaning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Javascript functions&lt;/strong&gt; expose key element behaviours and actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Events&lt;/strong&gt; communicate key actions or changes for other elements to react to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling&lt;/strong&gt; is made available through carefully chosen CSS variables and shadow parts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here are all the web component coding ideas that are touched by implementing the &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; component. See how we use them to build the component, or just reference the resources below!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements" rel="noopener noreferrer"&gt;Constructing web components&lt;/a&gt;&lt;/strong&gt; like a pro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/docs/testing/testing-package/" rel="noopener noreferrer"&gt;@open-wc/testing&lt;/a&gt;&lt;/strong&gt; provides useful testing helpers for putting our component on a web page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/guides/developing-components/testing/" rel="noopener noreferrer"&gt;@web/test-runner&lt;/a&gt;&lt;/strong&gt;  runs our tests in a real browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/docs/testing/helpers/#test-fixtures" rel="noopener noreferrer"&gt;Test Fixtures&lt;/a&gt;&lt;/strong&gt; set up an element on a page for testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks" rel="noopener noreferrer"&gt;connectedCallback&lt;/a&gt;&lt;/strong&gt;  initializes an element when inserted onto the page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://alligator.io/web-components/attributes-properties/" rel="noopener noreferrer"&gt;Attributes and properties&lt;/a&gt;&lt;/strong&gt;  can be set on custom elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://alligator.io/web-components/attributes-properties/#listening-for-changed-attributes" rel="noopener noreferrer"&gt;observedAttributes and attributeChangedCallback&lt;/a&gt;&lt;/strong&gt;  react to changes in attributes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks" rel="noopener noreferrer"&gt;disconnectedCallback&lt;/a&gt;&lt;/strong&gt;  cleans up after an element when it is removed from the document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/docs/testing/helpers/#testing-events" rel="noopener noreferrer"&gt;oneEvent&lt;/a&gt;&lt;/strong&gt;  tests that an event has occurred.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events" rel="noopener noreferrer"&gt;Custom Events&lt;/a&gt;&lt;/strong&gt;  let you dispatch events specific to your component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&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;&lt;/strong&gt;  encapsulates structure, style, and behaviour from the overall document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/part" rel="noopener noreferrer"&gt;Shadow Parts&lt;/a&gt;&lt;/strong&gt;  allow outside CSS to customize specific inner elements of a web component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:host" rel="noopener noreferrer"&gt;:host&lt;/a&gt;&lt;/strong&gt;  lets you style the web component itself from its shadow dom.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have also created a &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; web component you can install and use on your projects or use as reference:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Auroratide" rel="noopener noreferrer"&gt;
        Auroratide
      &lt;/a&gt; / &lt;a href="https://github.com/Auroratide/toggle-switch" rel="noopener noreferrer"&gt;
        toggle-switch
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Inventing a Light Bulb
&lt;/h2&gt;

&lt;p&gt;In each section, I will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discuss an aspect of web components, including why it is important&lt;/li&gt;
&lt;li&gt;Apply that aspect to building the &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; component, with code&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Semantics: The Schematic
&lt;/h3&gt;

&lt;p&gt;All good inventions start off with a drawing showing the design! Before building the web component, we need to think about &lt;em&gt;why&lt;/em&gt; we're building it.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyp028j63tr98cizsegap.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyp028j63tr98cizsegap.png" alt="Schematic of a light bulb, labelled with 'Semantics'."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, what is a &lt;strong&gt;web component&lt;/strong&gt; anyway?&lt;/p&gt;

&lt;p&gt;To answer that question, we need to answer a different question: What is a &lt;strong&gt;block quote&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;Well, it's pretty common for articles like this one to want to quote someone or something, for instance Thomas Edison:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To invent, you need a good imagination and a pile of junk.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can tell it's a quote of some kind by its formatting. And thankfully, the code to make this happen is quite 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;blockquote&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;To invent, you need a good imagination and a pile of junk.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/blockquote&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt; bit is an HTML tag with special meaning. When a developer uses it, they are declaring that the following text is a &lt;q&gt;section that is quoted from another source&lt;/q&gt;.&lt;/p&gt;

&lt;p&gt;You see, to achieve the formatting of a block quote, I didn't need to use the &lt;code&gt;blockquote&lt;/code&gt; element at all. I could have used some other HTML element and forced it to look like a quote, but while that may be useful for visual readers, it would not be useful to bots or to readers relying on assistive technology to read the page out loud.&lt;/p&gt;

&lt;p&gt;
  &lt;small&gt;What is &lt;strong&gt;assistive technology&lt;/strong&gt;?&lt;/small&gt;
  &lt;small&gt;Many people have disabilities which hinder them from using a site in common ways, and so they rely on assistive technology to navigate the internet. An example of such a technology is a screen reader, which verbally reads the page so vision-impaired people can understand the content.&lt;/small&gt; 

&lt;/p&gt;

&lt;p&gt;In other words, that &lt;code&gt;blockquote&lt;/code&gt; tag has special meaning, called &lt;strong&gt;semantics&lt;/strong&gt;, and those semantics allow anything reading the page to understand what the contents represent. Just like block quotes, most HTML elements have special semantics associated with them.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok Timothy, what do block quotes have to do with web components?&lt;/p&gt;

&lt;p&gt;So, our goal is to create a new HTML element, &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt;. Keeping in mind that most HTML elements have associated semantics, this leads us to an interesting insight:&lt;/p&gt;

&lt;p&gt;Web components create &lt;strong&gt;new semantics&lt;/strong&gt; through custom HTML elements.&lt;/p&gt;

&lt;p&gt;This is not normally the way I see web components described. Usually, web components are thought of in developer-centric terms like reusability and encapsulation. While those are indeed great goals and outcomes, framing a web component in terms of its semantics really helps capture why we are making it and what it will do.&lt;/p&gt;

&lt;p&gt;So, when it comes to building a new component, the first step is to understand what is its &lt;strong&gt;purpose&lt;/strong&gt;, and that helps you decide what its responsibilities and scope are.&lt;/p&gt;

&lt;p&gt;For our &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; component, it's pretty similar to a native HTML checkbox, but with one distinction: whereas a checkbox is either checked or unchecked, our switch element is either &lt;strong&gt;on or off&lt;/strong&gt;, which is a subtly different semantic.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Also, checkboxes have a third "&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input/checkbox#indeterminate" rel="noopener noreferrer"&gt;indeterminate&lt;/a&gt;" value that is neither checked nor unchecked. Such a third value does not make sense for an on/off switch.&lt;/small&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we have defined the what and why of the web component, we can create a bit of scaffolding! Let's start with a skeleton component:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// toggle-switch.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ToggleSwitch&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="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;elementName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle-switch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="nf"&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="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="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ToggleSwitch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elementName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ToggleSwitch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;customElements.define&lt;/code&gt; global function is what actually defines a web component, and it must be supplied with both the name of the element and a class extending an &lt;code&gt;HTMLElement&lt;/code&gt;. All of our eventual functionality will go into the &lt;code&gt;ToggleSwitch&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;As for testing, we are going to rely on two libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@open-wc/testing&lt;/code&gt;: A testing library providing useful helpers for mounting our component&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@web/test-runner&lt;/code&gt;: A program that will actually run our tests against a real browser
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm highlighting the "against a real browser" bit because doing so provides the highest confidence that the element as it behaves in tests will be the same as it behaves in the wild. This is opposed to using something like &lt;a href="https://github.com/jsdom/jsdom" rel="noopener noreferrer"&gt;jsdom&lt;/a&gt;, which has classically had poor support for web components.&lt;/p&gt;

&lt;p&gt;These libraries can be installed with npm:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -D @open-wc/testing @web/test-runner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;With that, all we need now is a skeletal test file and the ability to run said test:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// toggle-switch.spec.js&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;expect&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="s1"&gt;@open-wc/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./toggle-switch.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle-switch&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;works&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&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="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Running the test:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wtr --node-resolve ./**/*.spec.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And with that, we are finally ready to start building out our &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; component!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements" rel="noopener noreferrer"&gt;Constructing web components&lt;/a&gt;&lt;/strong&gt; like a pro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/docs/testing/testing-package/" rel="noopener noreferrer"&gt;@open-wc/testing&lt;/a&gt;&lt;/strong&gt; provides useful testing helpers for putting our component on a web page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/guides/developing-components/testing/" rel="noopener noreferrer"&gt;@web/test-runner&lt;/a&gt;&lt;/strong&gt;  runs our tests in a real browser.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Accessibility: The Cap
&lt;/h3&gt;

&lt;p&gt;The light bulb's cap is where it &lt;em&gt;accesses&lt;/em&gt; its power. Therefore, the cap represents &lt;strong&gt;accessibility&lt;/strong&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlqgy96lpr3y31d59jbq.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frlqgy96lpr3y31d59jbq.png" alt="The cap of a light bulb marked as 'Accessibility'."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility&lt;/strong&gt; is the practice of making things usable by as many people as possible, regardless of ability or disability. For example, if a blind person is relying on a screen reader to read the page out loud to them, then when they reach the toggle switch, they need to be made aware that the element is indeed a switch.&lt;/p&gt;

&lt;p&gt;It is a fairly broad topic that I cannot possibly cover in full here, but when it comes to web components, there are some key questions we can ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles" rel="noopener noreferrer"&gt;role&lt;/a&gt; or set of roles does our component serve?&lt;/li&gt;
&lt;li&gt;How will readers know what this component is and how to use it?&lt;/li&gt;
&lt;li&gt;In what ways might people use this component, and do we need to do anything special to accommodate those?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Accessible&lt;/strong&gt; components allow for multiple methods of interaction.&lt;/p&gt;

&lt;p&gt;Personally, I like using accessibility as a starting point so that good practices are built into the component earlier rather than later. Let's apply this concretely to the toggle switch!&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For coding, let's start by answering the key questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What role or set of roles does our component serve?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WAI-ARIA defines a &lt;a href="https://www.w3.org/TR/wai-aria-1.1/#switch" rel="noopener noreferrer"&gt;role called "switch"&lt;/a&gt; which actually fits our component perfectly. If we specify this role on our component, assistive technologies such as screen readers can inform their listeners that they can toggle something on and off.&lt;/p&gt;

&lt;p&gt;
  &lt;small&gt;What is &lt;strong&gt;WAI-ARIA&lt;/strong&gt;?&lt;/small&gt;
  &lt;small&gt;&lt;a href="https://www.w3.org/WAI/standards-guidelines/aria/" rel="noopener noreferrer"&gt;WAI-ARIA&lt;/a&gt; stands for Accessible Rich Internet Applications, and it essecially provides a framework for making advanced website stuff more accessible to people with disabilities.&lt;/small&gt; 

&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How will readers know what this component is and how to use it?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sometimes special labelling is needed to properly inform people who can't see the element what it is. In our case, we can rely on the switch role to do that: when a screen reader encounters an element marked as a switch, it should announce that the element is a switch without us having to do any extra work!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In what ways might people use this component, and do we need to do anything special to accommodate those?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Besides clicking on the switch, some people might not have or cannot use a mouse, and hence the switch should be interactable via keyboard.&lt;/p&gt;

&lt;p&gt;Taking these two concerns together, this means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We should set the &lt;code&gt;role&lt;/code&gt; attribute to &lt;code&gt;switch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We should make the element focusable, which can be done by setting &lt;code&gt;tabindex&lt;/code&gt; (see &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex" rel="noopener noreferrer"&gt;tabindex attribute&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To take care of the first item, let's first &lt;strong&gt;write a test&lt;/strong&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&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="s1"&gt;@open-wc/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accessibility&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default role&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;expect&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;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;switch&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This test does two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;strong&gt;fixture&lt;/strong&gt; which contains our new &lt;code&gt;toggle-switch&lt;/code&gt; element.&lt;/li&gt;
&lt;li&gt;Assert whether the element's accessible role is a switch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;fixture&lt;/code&gt; function provided by &lt;code&gt;@open-wc/testing&lt;/code&gt; is rather nifty! It essentially sets up an HTML document and puts our element onto the page, allowing us to mess with and inspect it.&lt;/p&gt;

&lt;p&gt;Our test implies we should set up our element to have the "switch" role immediately. To do that, we will rely on a &lt;strong&gt;lifecycle method&lt;/strong&gt; called &lt;code&gt;connectedCallback&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ToggleSwitch&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;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;role&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;switch&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;
  &lt;small&gt;What are &lt;strong&gt;lifecycle methods&lt;/strong&gt;?&lt;/small&gt;
  &lt;small&gt;Just like how all living things are born and eventually die, elements on a web page may come and go. Lifecycle methods represent key moments for an element, such as when it gets inserted on the page, removed from the page, or updated.&lt;/small&gt; 

&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;connectedCallback&lt;/code&gt; function is called every time an element gets inserted into the page, which is great for initialization!&lt;/p&gt;

&lt;p&gt;
  &lt;small&gt;What is different between &lt;strong&gt;connectedCallback&lt;/strong&gt; and the constructor?&lt;/small&gt;
  &lt;p&gt;&lt;small&gt;The constructor is called when an element is created for the first time, whereas the &lt;code&gt;connectedCallback&lt;/code&gt; is called just after the element is added to a page. One way to think of it is if the &lt;em&gt;same&lt;/em&gt; element is added to and removed from a page over and over again, the constructor is only called once, wherease &lt;code&gt;connectedCallback&lt;/code&gt; is called each time it's added back to the page.&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;Here's a good summary of what to do with the &lt;a href="https://stackoverflow.com/questions/59970043/custom-element-setup-constructor-vs-connectedcallback" rel="noopener noreferrer"&gt;constructor vs connectedCallback&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt; 



&lt;/p&gt;
&lt;p&gt;For our tabbable requirement, the test and initialization is very similar. Setting &lt;code&gt;tabindex="0"&lt;/code&gt; is all that's needed to make an element tabbable, allowing keyboard users to access our switch!&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="nc"&gt;ToggleSwitch&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;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;role&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;switch&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="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;tabindex&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;0&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, for our aria role, there's actually &lt;em&gt;a little bit more&lt;/em&gt; we need to do for our component to actually be an accessible switch. Conveniently, we'll be talking about that in the very next section...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/docs/testing/helpers/#test-fixtures" rel="noopener noreferrer"&gt;Test Fixtures&lt;/a&gt;&lt;/strong&gt; set up an element on a page for testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks" rel="noopener noreferrer"&gt;connectedCallback&lt;/a&gt;&lt;/strong&gt;  initializes an element when inserted onto the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Attributes: The Contact Wires
&lt;/h3&gt;

&lt;p&gt;Next on our light bulb are the contact wires which supply power to the part that lights up. This will represent &lt;strong&gt;attributes&lt;/strong&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpxpo4u723z547xw5bkz.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpxpo4u723z547xw5bkz.png" alt="The contact wires of a light bulb marked as 'Attributes'."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;HTML elements have &lt;strong&gt;attributes&lt;/strong&gt; which basically tell more about the element's current state or how it should work. For example, the &lt;code&gt;&amp;lt;blockquote&amp;gt;&lt;/code&gt; element has an attribute called &lt;code&gt;cite&lt;/code&gt; which is a link to the source of the quote.&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;blockquote&lt;/span&gt; &lt;span class="na"&gt;cite=&lt;/span&gt;&lt;span class="s"&gt;"https://html.spec.whatwg.org/#the-blockquote-element"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;If the cite attribute is present, it must be a valid URL. . .&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/blockquote&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As such, custom elements are also able to expose attributes! Their three key uses are for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State&lt;/strong&gt;: Such as an element's initial or current value&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration&lt;/strong&gt;: Such as whether the element is disabled, has input boundaries, and so forth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nuanced Meaning&lt;/strong&gt;: Specifying more details to an element's semantic value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Attributes&lt;/strong&gt; surface important state, configuration, and nuanced meaning.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Regarding &lt;strong&gt;nuanced meaning&lt;/strong&gt;, a good example is the &lt;code&gt;cite&lt;/code&gt; attribute on &lt;code&gt;blockquote&lt;/code&gt;. It doesn't have a functional purpose, nor does it configure the element in any way. It just enhances the element's meaning: it's not just any quote, but a quote from a particular source.&lt;/small&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Building out the &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; element, there is at least one important state we want to convey with an attribute: whether the switch is on or off. Let's follow these three steps for creating that attribute:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Determine a &lt;strong&gt;name&lt;/strong&gt; and &lt;strong&gt;allowed values&lt;/strong&gt; for the attribute.&lt;/li&gt;
&lt;li&gt;Set a &lt;strong&gt;property&lt;/strong&gt; for the attribute.&lt;/li&gt;
&lt;li&gt;Determine whether a &lt;strong&gt;change&lt;/strong&gt; in the attribute triggers a change on the element.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To mimic a bit how the vanilla checkbox input element works, we'll call our attribute &lt;code&gt;checked&lt;/code&gt;, and it will be a boolean attribute, meaning its presence or absence will represent true or false respectively.&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;!-- off --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- on --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;toggle-switch&lt;/span&gt; &lt;span class="na"&gt;checked&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/toggle-switch&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Setting a &lt;strong&gt;property&lt;/strong&gt; for the element's class essentially declares the attribute is important. In truth, any element can have any attribute, so by creating a property we communicate that &lt;code&gt;checked&lt;/code&gt; is important for the toggle switch.&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;ToggleSwitch&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="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;checked&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasAttribute&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="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;checked&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggleAttribute&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="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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And the interesting question: does a change in &lt;code&gt;checked&lt;/code&gt; require a change on the element?&lt;/p&gt;

&lt;p&gt;I can think of at least two things that should change when the &lt;code&gt;checked&lt;/code&gt; attribute is added or removed from the toggle switch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The switch should animate (but we'll get to that when we discuss styling)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;aria-checked&lt;/code&gt; attribute should reflect the &lt;code&gt;checked&lt;/code&gt; attribute.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...&lt;em&gt;what&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;Recall from earlier that we are relying on the &lt;a href="https://www.w3.org/TR/wai-aria-1.1/#switch" rel="noopener noreferrer"&gt;switch role&lt;/a&gt; for accessibility. That role &lt;em&gt;requires&lt;/em&gt; that an accessibility attribute called &lt;code&gt;aria-checked&lt;/code&gt; be set to either "true" or "false".&lt;/p&gt;

&lt;p&gt;So, when &lt;code&gt;checked&lt;/code&gt; is present, &lt;code&gt;aria-checked&lt;/code&gt; must be "true", and when &lt;code&gt;checked&lt;/code&gt; is absent, &lt;code&gt;aria-checked&lt;/code&gt; must be "false".&lt;/p&gt;

&lt;p&gt;Let's write a test for that!&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;it&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 attribute is updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;expect&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;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aria-checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&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;toggleAttribute&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;expect&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;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aria-checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In this test, we first ensure that an unchecked toggle switch starts with an &lt;code&gt;aria-checked&lt;/code&gt; of "false", indicating it is off to accessibility stuff. Then, we add the &lt;code&gt;checked&lt;/code&gt; attribute and verify that &lt;code&gt;aria-checked&lt;/code&gt; has changed to "true".&lt;/p&gt;

&lt;p&gt;Now, to actually accomplish this in code requires using a cool feature of web components: &lt;code&gt;observedAttributes&lt;/code&gt; and &lt;code&gt;attributeChangedCallback&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;observedAttributes&lt;/code&gt; is just a list of attributes that the element should react to if changed.&lt;/li&gt;
&lt;li&gt;And &lt;code&gt;attributeChangedCallback&lt;/code&gt; is the function that gets fired when any of the listed attributes change.
&lt;/li&gt;
&lt;/ul&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;ToggleSwitch&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="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;checked&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&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="k"&gt;this&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;aria-checked&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;checked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;And finally, we will want to make sure the initial state is taken care of in &lt;code&gt;connectedCallback&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;ToggleSwitch&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;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;aria-checked&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;checked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;&lt;strong&gt;Code Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://alligator.io/web-components/attributes-properties/" rel="noopener noreferrer"&gt;Attributes and properties&lt;/a&gt;&lt;/strong&gt;  can be set on custom elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://alligator.io/web-components/attributes-properties/#listening-for-changed-attributes" rel="noopener noreferrer"&gt;observedAttributes and attributeChangedCallback&lt;/a&gt;&lt;/strong&gt;  react to changes in attributes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Javascript: The Filament
&lt;/h3&gt;

&lt;p&gt;And now for the part of the bulb that actually glows: the filament! As the heart of the light bulb, it's fitting for the filament to represent the heart of our component, the &lt;strong&gt;javascript API&lt;/strong&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3y3dcxxswtdld7c3vh9.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3y3dcxxswtdld7c3vh9.png" alt="The filament of a light bulb marked as 'Javascript'."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;
  &lt;small&gt;What is an &lt;strong&gt;API&lt;/strong&gt;?&lt;/small&gt;
  &lt;p&gt;&lt;small&gt;API stands for Application Programming Interface. If you think of a car as a program, then its API would be the steering wheel, gas pedal, and brake. You cannot directly manipulate what the engine does and can only do so through those three accessible things.&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;As such, an API exposes ways to use an element without needing to know all of its messy guts.&lt;/small&gt;&lt;/p&gt; 



&lt;/p&gt;
&lt;p&gt;Although a web component could be as simple as just coloring text, custom elements are additionally useful for bundling complex functionality into a single doodad. For example, the toggle switch component must allow someone to toggle it on and off, and so a click action must be bound to do that.&lt;/p&gt;

&lt;p&gt;Perhaps that's not surprising, so what I find useful is to think of those potential actions as &lt;strong&gt;public javascript functions&lt;/strong&gt;. Another way of putting it, if a reader is able to click the component to toggle it, then there should be a &lt;code&gt;toggle()&lt;/code&gt; function available so that &lt;em&gt;other javascript code&lt;/em&gt; can simulate the reader's action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Javascript functions&lt;/strong&gt; expose key element behaviours and actions.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the toggle switch, when someone clicks on it, the element should go from off to on, or from on to off. As usual, we start with a test!&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;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggling on and off&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;via clicking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;false&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;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;true&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;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Here, we are able to use the &lt;code&gt;click()&lt;/code&gt; function to simulate someone clicking the element.&lt;/p&gt;

&lt;p&gt;To make this test pass, all we have to do is listen for a "click" event and toggle the &lt;code&gt;checked&lt;/code&gt; state. We will do this in &lt;code&gt;connectedCallback&lt;/code&gt; since that's a good place to handle initialization.&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;ToggleSwitch&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;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="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;checked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&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;Looks great, except! Remember our key point:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Key element behaviours are exposed as &lt;strong&gt;Javascript functions&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means we should have a &lt;code&gt;toggle()&lt;/code&gt; method exposing this is a key way not only readers can interact with the component, but other javascript code can too.&lt;/p&gt;

&lt;p&gt;In fact, we'll make test for this as well!&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;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggling on and off&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;via the api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;false&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;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;true&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;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This test is extremely similar to the previous test, with the primary difference this uses a public function (&lt;code&gt;toggle()&lt;/code&gt;) rather than a user action (clicking).&lt;/p&gt;

&lt;p&gt;Doing this allows two things. First, we can actually simplify the event listener from above to use our new function:&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;ToggleSwitch&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;toggle&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="k"&gt;this&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="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;checked&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;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;toggle&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;But additionally, we can now &lt;strong&gt;clean up&lt;/strong&gt; the event listener with the &lt;code&gt;disconnectedCallback&lt;/code&gt; hook!&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;ToggleSwitch&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;disconnectedCallback&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;removeEventListener&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;toggle&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;As a mirror to &lt;code&gt;connectedCallback&lt;/code&gt;, the &lt;code&gt;disconnectedCallback&lt;/code&gt; function is called every time the element is removed from the document. It is most useful for cleaning up listeners it may have set up elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks" rel="noopener noreferrer"&gt;disconnectedCallback&lt;/a&gt;&lt;/strong&gt;  cleans up after an element when it is removed from the document.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Events: The Inert Gas
&lt;/h3&gt;

&lt;p&gt;So it turns out there's a part of a light bulb you can't see but is nonetheless important for it to work: the inert gas! The bulb is filled with special air that extends the lifetime of the filament.&lt;/p&gt;

&lt;p&gt;Continuing our Light Bulb of Web Components, the gas is represented by the &lt;strong&gt;event API&lt;/strong&gt;, stuff happening under the surface but significant for other things to react to changes in our component.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonlbr7ty80d04am46kl0.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonlbr7ty80d04am46kl0.png" alt="The empty part of a light bulb marked as 'Events'."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;event&lt;/strong&gt; is essentially a tidbit of code declaring that something happened, for instance "Hey, somebody toggled me on!" By emitting an event like this, &lt;strong&gt;listeners&lt;/strong&gt; can react with some appropriate action.&lt;/p&gt;

&lt;p&gt;When building a web component, we should think about what events it should emit that other elements may need to react to. In fact, this is the primary mechanism by which our &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; element will even be useful!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Events&lt;/strong&gt; communicate key actions or changes for other elements to react to.&lt;/p&gt;

&lt;p&gt;In essence, our goal is for our element to be used like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggleSwitch&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;toggle-switch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;toggleSwitch&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;toggle-switch: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="nx"&gt;e&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;// code toggling light/dark mode&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://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thinking about our &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; component again, what are the key events we want it to emit? For the most part, there's just one: whether its state changes from off to on or vice versa.&lt;/p&gt;

&lt;p&gt;So, whenever the &lt;code&gt;checked&lt;/code&gt; state changes, the element should emit an event!&lt;/p&gt;

&lt;p&gt;To write a test, we must ask three questions.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is the event's &lt;strong&gt;name&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When&lt;/strong&gt; does the event occur?&lt;/li&gt;
&lt;li&gt;What &lt;strong&gt;details&lt;/strong&gt; should be shipped with the event?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The answers to these questions will fit into this nice testing template:&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;oneEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&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="s1"&gt;@open-wc/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;events&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;turned on&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="cm"&gt;/* (2) WHEN */&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;detail&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;oneEvent&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="cm"&gt;/* (1) NAME */&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="cm"&gt;/* (3) ASSERT DETAILS */&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;Answering the questions...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: Since our event represents a &lt;em&gt;change&lt;/em&gt; in the state, we'll call the event "toggle-switch:change".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When&lt;/strong&gt;: Let's emit the event any time &lt;code&gt;checked&lt;/code&gt; is added or removed from the element.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Details&lt;/strong&gt;: Events can carry additional information so that listeners know both &lt;em&gt;what&lt;/em&gt; happened and anything else that may be relevant. For our one event, it's probably important to know whether the switch was toggled on or toggled off, so we'll add that to details.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If we plug these things into our testing template, we get a decent test!&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;oneEvent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&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="s1"&gt;@open-wc/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;events&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;turned on&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;setTimeout&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;el&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="kc"&gt;true&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;detail&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;oneEvent&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle-switch:change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The two important functions in this test are &lt;code&gt;setTimeout&lt;/code&gt; (provided by Javascript) and &lt;code&gt;oneEvent&lt;/code&gt; (provided by open-wc).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;oneEvent&lt;/code&gt; just waits for one event to occur, and times out with a failure if the event never occurs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setTimeout&lt;/code&gt; adds our toggle to a list of things for Javascript to do eventually. It's needed because if we &lt;em&gt;didn't&lt;/em&gt; use it, our event could potentially fire before we even started listening for it!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ok, let's actually emit the event now!&lt;/p&gt;

&lt;p&gt;Since our event is custom to our new element, we will dispatch a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events" rel="noopener noreferrer"&gt;Custom Event&lt;/a&gt;, and since we want to do it any time &lt;code&gt;checked&lt;/code&gt; changes, we'll perform the dispatch with the code that reacts to when that attribute changes.&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;ToggleSwitch&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;attributeChangedCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&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="k"&gt;this&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;aria-checked&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;checked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;dispatchEvent&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;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle-switch: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="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;checked&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;checked&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;&lt;strong&gt;Code Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/docs/testing/helpers/#testing-events" rel="noopener noreferrer"&gt;oneEvent&lt;/a&gt;&lt;/strong&gt;  tests that an event has occurred.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events" rel="noopener noreferrer"&gt;Custom Events&lt;/a&gt;&lt;/strong&gt;  let you dispatch events specific to your component.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Styling: The Globe
&lt;/h3&gt;

&lt;p&gt;So, we've done &lt;em&gt;all this coding&lt;/em&gt; so far, but we can't actually &lt;em&gt;see&lt;/em&gt; the switch yet... Let's finally put the globe on our light bulb by adding some &lt;strong&gt;styling&lt;/strong&gt; to our element!&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy3wkbrrotcv7qwg2k64.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwy3wkbrrotcv7qwg2k64.png" alt="The globe of a light bulb marked as 'Styling'."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be honest, styling web components is entirely deserving of its own article, made both interesting and complicated by a tiny thing called the &lt;strong&gt;Shadow DOM&lt;/strong&gt;. MDN covers &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM" rel="noopener noreferrer"&gt;using the shadow dom&lt;/a&gt; in good detail, so for the purposes of this article we'll talk about it just enough to style the &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Shadow DOM allows web components to, in essence, carry around their own personal document hidden from the primary web page document. It's kind of like... &lt;strong&gt;flowers&lt;/strong&gt;.&lt;/p&gt;

&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdd9q6kchhklq9uiqy40.png" alt="Yellow flowers."&gt;&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@mrjbardia?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;bardia Hashemirad&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/yellow-flowers?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a gardener, you can't tell a flower what shape to take or how many petals to have, as that's determined by its own DNA. You &lt;em&gt;can&lt;/em&gt; determine how many flowers are in your garden, and maybe you can influence some of the flower's colors by feeding it colored water, but beyond that you don't get much say.&lt;/p&gt;

&lt;p&gt;Similarly, an element's shadow dom (flower) is &lt;em&gt;encapsulated&lt;/em&gt; from the rest of the document, meaning the document (gardener) cannot directly influence elements defined in the shadow dom; neither can different web components clash with each other.&lt;/p&gt;



&lt;p&gt;This turns out to be rather important for &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; because we now have competing concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We must use the shadow dom to give our element a decent default "switch look"&lt;/li&gt;
&lt;li&gt;But we also want developers to customize it &lt;em&gt;from outside the component&lt;/em&gt; to fit their website's look and feel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These competing concerns are incredibly common, and therefore the shadow dom is actually not &lt;em&gt;completely&lt;/em&gt; impenetrable. Although the parent document can never arbitrarily customize stuff in the shadow dom, there are a few exceptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties" rel="noopener noreferrer"&gt;CSS variables&lt;/a&gt; can take on values from beyond the shadow dom.&lt;/li&gt;
&lt;li&gt;Elements within the shadow dom can be assigned &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/part" rel="noopener noreferrer"&gt;shadow part names&lt;/a&gt; which can be directly selected with CSS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These exceptions form a web component's &lt;strong&gt;Styling API&lt;/strong&gt;, specifically defined opportunities for customization. And just like how we have to intentionally decide what attributes, javascript functions, and events to expose, we also have to choose what CSS variables or parts can be styled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Styling&lt;/strong&gt; is made available through carefully chosen CSS variables and shadow parts.&lt;/p&gt;

&lt;p&gt;
  &lt;small&gt;Earlier I said we "must" use the shadow dom. Why?&lt;/small&gt;
  &lt;p&gt;&lt;small&gt;In our case, we want to maintain the &lt;em&gt;internal structure&lt;/em&gt; of the element, which means it shouldn't be exposed to the outside. Deciding what goes in shadow dom or not is important for creating an element's style API, but is complex enough to merit its own article.&lt;/small&gt;&lt;/p&gt;
&lt;p&gt;&lt;small&gt;&lt;a href="https://stackoverflow.com/questions/61626493/slotted-css-selector-for-nested-children-in-shadowdom-slot/61631668#61631668" rel="noopener noreferrer"&gt;This stack overflow post&lt;/a&gt; helped me understand this concept and links to other useful resources.&lt;/small&gt;&lt;/p&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2qz4b1c6ifsklt0rn2wl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At long last, let's style this web component!&lt;/p&gt;

&lt;p&gt;To make the switch easy to customize, we are going to minimally style it. Our base switch is gonna be just a square that moves back and forth along a track like this:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/RwgeKOj?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;First, we must attach a &lt;strong&gt;shadow root&lt;/strong&gt; to the element and create a basic template for our element.&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;template&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;template&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;style&amp;gt;
    /* CSS HERE */
  &amp;lt;/style&amp;gt;
  &amp;lt;span part="track"&amp;gt;
    &amp;lt;span part="slider"&amp;gt;&amp;lt;/span&amp;gt;
  &amp;lt;/span&amp;gt;
`&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ToggleSwitch&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="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="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneNode&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="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;Of note, we want developers using this toggle switch to be able to customize both the sliding bit and the track underneath it, so to make that possible we are assigning &lt;strong&gt;shadow parts&lt;/strong&gt; to each element. This will make it possible for users to style those specific components like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;toggle-switch&lt;/span&gt;&lt;span class="nd"&gt;::part&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;slider&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&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 the basic template structure done, all that's left is adding CSS! All CSS added will go into the &lt;code&gt;style&lt;/code&gt; tag in the template above.&lt;/p&gt;

&lt;p&gt;First, let's give the element some basic sizing.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:host&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&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;Two things of interest here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;:host&lt;/code&gt; selector is special in the context of shadow dom. It basically means "style the thing &lt;em&gt;that contains&lt;/em&gt; the shadow dom", which is the web component itself. In our case, this styles the &lt;code&gt;toggle-switch&lt;/code&gt; tag.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;span&lt;/code&gt; only selects spans &lt;em&gt;within the shadow dom&lt;/em&gt; of the element. It does &lt;em&gt;not&lt;/em&gt; globally style all spans on the page! That's part of the power of encapsulation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, we'll style the track and slider to look like our squareish examples:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;part&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"track"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#dddddd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;part&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"slider"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#777777&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;vertical-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;text-top&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And for the last part, we need to style what the component looks like when it has been checked. Recall that the &lt;code&gt;checked&lt;/code&gt; attribute on the &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; tag determines its on/off state. This can be selected for with an attribute selector using &lt;code&gt;:host&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;part&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"track"&lt;/span&gt;&lt;span class="o"&gt;],&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;part&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"slider"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="m"&gt;256ms&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;:host&lt;/span&gt;&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="nt"&gt;checked&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;part&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"slider"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100%&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;strong&gt;Code Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&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;&lt;/strong&gt;  encapsulates structure, style, and behaviour from the overall document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/part" rel="noopener noreferrer"&gt;Shadow Parts&lt;/a&gt;&lt;/strong&gt;  allow outside CSS to customize specific inner elements of a web component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:host" rel="noopener noreferrer"&gt;:host&lt;/a&gt;&lt;/strong&gt;  lets you style the web component itself from its shadow dom.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  We Invented a Light Bulb!
&lt;/h2&gt;

&lt;p&gt;And with that, we just covered the &lt;strong&gt;six key aspects&lt;/strong&gt; to building great web components! And in the process we built both a light bulb &lt;em&gt;and&lt;/em&gt; a toggle switch!&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r2nq00x9t96i6id2tto.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5r2nq00x9t96i6id2tto.png" alt="Light bulb, with parts represented by accessibility, attributes, javascript, events, and styling."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Components create &lt;strong&gt;new semantics&lt;/strong&gt; through custom elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessible&lt;/strong&gt; components allow for multiple methods of interaction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attributes&lt;/strong&gt; surface important state, configuration, and nuanced meaning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Javascript functions&lt;/strong&gt; expose key element behaviours and actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Events&lt;/strong&gt; communicate key actions or changes for other elements to react to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling&lt;/strong&gt; is made available through carefully chosen CSS variables and shadow parts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But... is it truly complete?&lt;/p&gt;

&lt;p&gt;Almost! There are a few things I skipped over to simplify the tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accessibility: How do we label the switch? Can we integrate this with the HTML &lt;code&gt;label&lt;/code&gt; element?&lt;/li&gt;
&lt;li&gt;Javascript: When someone tabs to the toggle, can they activate it by pressing Enter or Space?&lt;/li&gt;
&lt;li&gt;Attributes: Can a toggle switch be &lt;code&gt;disabled&lt;/code&gt; like other HTML input controls?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to try to tackle these issues yourself! Or, see how it all works in my implementation of the &lt;code&gt;&amp;lt;toggle-switch&amp;gt;&lt;/code&gt; element on Github.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Auroratide" rel="noopener noreferrer"&gt;
        Auroratide
      &lt;/a&gt; / &lt;a href="https://github.com/Auroratide/toggle-switch" rel="noopener noreferrer"&gt;
        toggle-switch
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Full Code
&lt;/h2&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;template&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;template&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
  &amp;lt;style&amp;gt;
    :host {
      display: inline-block;
      width: 2em;
      height: 1em;
      cursor: pointer;
    }

    span {
      box-sizing: border-box;
      display: inline-block;
      line-height: 1;
    }

    [part="track"] {
      width: 100%;
      height: 100%;
      background-color: #dddddd;
      text-align: left;
    }

    [part="slider"] {
      width: 50%;
      height: 100%;
      background-color: #777777;
      vertical-align: text-top;
    }

    [part="track"], [part="slider"] {
      transition: all 256ms;
    }

    :host([checked]) [part="slider"] {
      transform: translateX(100%);
    }
  &amp;lt;/style&amp;gt;

  &amp;lt;span part="track"&amp;gt;
    &amp;lt;span part="slider"&amp;gt;&amp;lt;/span&amp;gt;
  &amp;lt;/span&amp;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="nc"&gt;ToggleSwitch&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="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;elementName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle-switch&lt;/span&gt;&lt;span class="dl"&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;checked&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;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="nf"&gt;attachShadow&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cloneNode&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="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;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;role&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;switch&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="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;tabindex&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;0&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="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;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;toggle&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&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;toggle&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;checked&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="k"&gt;this&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;aria-checked&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;checked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&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;dispatchEvent&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;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle-switch: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="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;checked&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;checked&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="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;checked&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasAttribute&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="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nf"&gt;checked&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggleAttribute&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="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;toggle&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="k"&gt;this&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="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;checked&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="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ToggleSwitch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elementName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ToggleSwitch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expect&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="s1"&gt;@open-wc/testing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle-switch&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accessibility&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default role&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nf"&gt;expect&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;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;role&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;switch&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;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tabbing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nf"&gt;expect&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;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tabindex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0&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;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;attributes&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&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 attribute is updated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nf"&gt;expect&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;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aria-checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&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;toggleAttribute&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nf"&gt;expect&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;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aria-checked&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&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;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggling on and off&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;via clicking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;false&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;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;true&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;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&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="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;via the api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;false&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;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;true&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;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="nf"&gt;expect&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="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&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="p"&gt;})&lt;/span&gt;

  &lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;events&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;turned on&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &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="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="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;lt;toggle-switch&amp;gt;&amp;lt;/toggle-switch&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nf"&gt;setTimeout&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;el&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="kc"&gt;true&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;detail&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;oneEvent&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;toggle-switch:change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&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="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements" rel="noopener noreferrer"&gt;Constructing web components&lt;/a&gt;&lt;/strong&gt; like a pro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/docs/testing/testing-package/" rel="noopener noreferrer"&gt;@open-wc/testing&lt;/a&gt;&lt;/strong&gt; provides useful testing helpers for putting our component on a web page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/guides/developing-components/testing/" rel="noopener noreferrer"&gt;@web/test-runner&lt;/a&gt;&lt;/strong&gt;  runs our tests in a real browser.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/docs/testing/helpers/#test-fixtures" rel="noopener noreferrer"&gt;Test Fixtures&lt;/a&gt;&lt;/strong&gt; set up an element on a page for testing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks" rel="noopener noreferrer"&gt;connectedCallback&lt;/a&gt;&lt;/strong&gt;  initializes an element when inserted onto the page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://alligator.io/web-components/attributes-properties/" rel="noopener noreferrer"&gt;Attributes and properties&lt;/a&gt;&lt;/strong&gt;  can be set on custom elements.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://alligator.io/web-components/attributes-properties/#listening-for-changed-attributes" rel="noopener noreferrer"&gt;observedAttributes and attributeChangedCallback&lt;/a&gt;&lt;/strong&gt;  react to changes in attributes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks" rel="noopener noreferrer"&gt;disconnectedCallback&lt;/a&gt;&lt;/strong&gt;  cleans up after an element when it is removed from the document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://open-wc.org/docs/testing/helpers/#testing-events" rel="noopener noreferrer"&gt;oneEvent&lt;/a&gt;&lt;/strong&gt;  tests that an event has occurred.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events" rel="noopener noreferrer"&gt;Custom Events&lt;/a&gt;&lt;/strong&gt;  let you dispatch events specific to your component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&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;&lt;/strong&gt;  encapsulates structure, style, and behaviour from the overall document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/part" rel="noopener noreferrer"&gt;Shadow Parts&lt;/a&gt;&lt;/strong&gt;  allow outside CSS to customize specific inner elements of a web component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:host" rel="noopener noreferrer"&gt;:host&lt;/a&gt;&lt;/strong&gt;  lets you style the web component itself from its shadow dom.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>html</category>
      <category>webdev</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>A Typewriter, but using a New HTML Tag</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Thu, 09 Sep 2021 19:55:08 +0000</pubDate>
      <link>https://dev.to/auroratide/a-typewriter-but-using-a-new-html-tag-60i</link>
      <guid>https://dev.to/auroratide/a-typewriter-but-using-a-new-html-tag-60i</guid>
      <description>&lt;p&gt;So last time, I made a &lt;a href="https://dev.to/auroratide/a-typewriter-but-with-no-html-css-or-js-1bgd"&gt;typewriter animation without HTML, CSS, nor Javascript&lt;/a&gt;. What happens if instead of using nothing, we allow ourselves to use... &lt;em&gt;everything&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/MWoJdda?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;All this is achieved with a fancy new HTML tag, &lt;code&gt;&amp;lt;typewritten-text&amp;gt;&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;This is a &lt;span class="nt"&gt;&amp;lt;typewritten-text&amp;gt;&amp;lt;strong&amp;gt;&lt;/span&gt;typewriter effect!&lt;span class="nt"&gt;&amp;lt;/strong&amp;gt;&amp;lt;/typewritten-text&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Find out how to install and use it here:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Auroratide" rel="noopener noreferrer"&gt;
        Auroratide
      &lt;/a&gt; / &lt;a href="https://github.com/Auroratide/typewritten-text" rel="noopener noreferrer"&gt;
        typewritten-text
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The text types itself out!
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  A New HTML Tag?
&lt;/h2&gt;

&lt;p&gt;The HTML standard allows developers to define &lt;strong&gt;custom elements&lt;/strong&gt; through &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" rel="noopener noreferrer"&gt;Web Components&lt;/a&gt;. Making a new element just requires a handful of Javascript, from there letting you define as much or as little functionality as needed.&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;MyElement&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="c1"&gt;// code for how the element looks and behaves&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="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-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MyElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;typewritten-text&lt;/code&gt; element is one such web component, designed to provide a semantic, flexible, and reusable typewriter component!&lt;/p&gt;

&lt;p&gt;Since web components are native browser technology, they are meant to work with most of our &lt;a href="https://custom-elements-everywhere.com/" rel="noopener noreferrer"&gt;beloved frameworks&lt;/a&gt; out of the box &lt;small&gt;(looking at you, &lt;em&gt;React&lt;/em&gt;...)&lt;/small&gt;. That's one of my favorite things about them!&lt;/p&gt;

&lt;p&gt;Granted, the developer experience can be... painful sometimes. This innocent little element turned out to be &lt;em&gt;much much harder&lt;/em&gt; than I originally thought in order to achieve all my goals for it.&lt;/p&gt;
&lt;h2&gt;
  
  
  The &lt;code&gt;typewritten-text&lt;/code&gt; Element
&lt;/h2&gt;

&lt;p&gt;Once Javascript enters the arena, basically anything becomes possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No need for monospace requirements! The inner text can be of any font or size; in fact, it can mix fonts if you want.&lt;/li&gt;
&lt;li&gt;Built-in multiline support, for if you want to type out a longer sentence or two.&lt;/li&gt;
&lt;li&gt;A very simple interface; you can basically use it like any standard HTML tag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And of course, I put in the effort to make it as &lt;strong&gt;accessible&lt;/strong&gt; as possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It represents its textual content regardless of current typed state, especially useful for those using Assistive Technologies.&lt;/li&gt;
&lt;li&gt;The blinking cursor animation is disabled for people who &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion" rel="noopener noreferrer"&gt;prefer reduced motion&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;No content-shifting either! The element's size is always the size of its content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perhaps the most interesting feature is its &lt;strong&gt;events&lt;/strong&gt;. The element dispatches events when characters are typed or the phrase is finished. By listening to those events, you can use the magic of code to make the typewriter do any custom behaviour that's desired!&lt;/p&gt;

&lt;p&gt;For example, starting another typewritten text:&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;first&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;typewritten-text:phrasetyped&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="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;second&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Showcasing
&lt;/h2&gt;

&lt;p&gt;Here's a couple of nifty things you can do with the &lt;code&gt;typewritten-text&lt;/code&gt; component!&lt;/p&gt;
&lt;h3&gt;
  
  
  Typewriter Cycle
&lt;/h3&gt;

&lt;p&gt;Using &lt;strong&gt;events&lt;/strong&gt;, it's simple to cycle through different texts to type out.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/BaZWWwQ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;small&gt;The &lt;code&gt;typewritten-text&lt;/code&gt; element is designed to be very basic so it can be used in as many ways as possible, which is why the cycle effect is not built-in. A different web component could be made to encapsulate the effect, though!&lt;/small&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Character Dialog
&lt;/h3&gt;

&lt;p&gt;Characters tend to talk with a typewriter animation also!&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Hit &lt;code&gt;Rerun&lt;/code&gt; at the bottom of the frame to see the animation again.&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/rNwyYyW?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
&lt;h2&gt;
  
  
  Find out more
&lt;/h2&gt;

&lt;p&gt;All information on how to install and use the &lt;code&gt;typewritten-text&lt;/code&gt; component can be found on github!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Auroratide" rel="noopener noreferrer"&gt;
        Auroratide
      &lt;/a&gt; / &lt;a href="https://github.com/Auroratide/typewritten-text" rel="noopener noreferrer"&gt;
        typewritten-text
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The text types itself out!
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;I may soon write a little more about the process of actually making (&lt;em&gt;and testing&lt;/em&gt;) a web component.&lt;/p&gt;

</description>
      <category>html</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>A Typewriter, but with no HTML, CSS, or JS?!</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Sun, 29 Aug 2021 19:49:21 +0000</pubDate>
      <link>https://dev.to/auroratide/a-typewriter-but-with-no-html-css-or-js-1bgd</link>
      <guid>https://dev.to/auroratide/a-typewriter-but-with-no-html-css-or-js-1bgd</guid>
      <description>&lt;p&gt;Apparently a battle of sorts has erupted amongst devs clamoring for the title of Best Typewriter Animator Person.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/alvaromontoro"&gt;@alvaromontoro&lt;/a&gt; started with a &lt;a href="https://dev.to/alvaromontoro/typewriter-effect-with-css-38im"&gt;Typewriter effect in CSS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/afif"&gt;@afif&lt;/a&gt; then gave us &lt;a href="https://dev.to/afif/a-scalable-css-only-typewriter-effect-2opn"&gt;A scalable CSS only Typewriter Effect&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;@inhuofficial has promised us an HTML-only typewriter&lt;/li&gt;
&lt;li&gt;And &lt;a class="mentioned-user" href="https://dev.to/alvaromontoro"&gt;@alvaromontoro&lt;/a&gt; came back with an &lt;a href="https://dev.to/alvaromontoro/animated-no-element-typewriter-2835"&gt;Animated no-element typewriter &lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the classic spirit of one-uppery that has arisen, it was only a matter of time before &lt;em&gt;someone&lt;/em&gt;, &lt;em&gt;somewhere&lt;/em&gt; took on the most legendary of tasks: to create a typewriter animation for the web without using &lt;em&gt;anything&lt;/em&gt;. No Javascript. No CSS. Not even HTML.&lt;/p&gt;

&lt;p&gt;Behold, the power of &lt;strong&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG"&gt;Scalable Vector Graphics&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/auroratide/embed/ExXVdZG?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Ok but actually &lt;strong&gt;don't use this&lt;/strong&gt; if you want a typewriter animation! It's got browser compatibility and accessibility issues, but at least it's a cute experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The SVG spec has something called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG/SVG_animation_with_SMIL"&gt;Synchronized Multimedia Integration Language&lt;/a&gt; (SMIL) which allows animations to be defined in the XML document directly.&lt;/p&gt;

&lt;p&gt;For example, consider the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animate"&gt;animate&lt;/a&gt; tag. When made a child of some shape like &lt;code&gt;rect&lt;/code&gt;, you can choose what attribute to animate over time and specify the way in which it changes.&lt;/p&gt;

&lt;p&gt;So for example, the text cursor is given a simple blink animation just by adjusting the width of a rectangle between 0 and 1, and doing it discretely so it blinks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;rect&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"black"&lt;/span&gt; &lt;span class="na"&gt;x=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;y=&lt;/span&gt;&lt;span class="s"&gt;"4"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;animate&lt;/span&gt;
    &lt;span class="na"&gt;attributeName=&lt;/span&gt;&lt;span class="s"&gt;"width"&lt;/span&gt;
    &lt;span class="na"&gt;calcMode=&lt;/span&gt;&lt;span class="s"&gt;"discrete"&lt;/span&gt;
    &lt;span class="na"&gt;values=&lt;/span&gt;&lt;span class="s"&gt;"1; 0"&lt;/span&gt;
    &lt;span class="na"&gt;dur=&lt;/span&gt;&lt;span class="s"&gt;"1s"&lt;/span&gt;
    &lt;span class="na"&gt;repeatCount=&lt;/span&gt;&lt;span class="s"&gt;"indefinite"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/rect&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the first time I've ever used SMIL, so almost certainly someone smarter than me can find a better way than adjusting an overlaying white rectangle!&lt;/p&gt;

</description>
      <category>codepen</category>
      <category>svg</category>
      <category>html</category>
    </item>
    <item>
      <title>Tips That Made My Site More Accessible</title>
      <dc:creator>Timothy Foster</dc:creator>
      <pubDate>Sat, 28 Aug 2021 21:47:02 +0000</pubDate>
      <link>https://dev.to/auroratide/tips-that-made-my-site-more-accessible-1omj</link>
      <guid>https://dev.to/auroratide/tips-that-made-my-site-more-accessible-1omj</guid>
      <description>&lt;p&gt;If you want to learn more about creating accessible content, I highly recommend giving this article by @inhuofficial a read:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;div class="ltag__link__content"&gt;
    &lt;div class="missing"&gt;
      &lt;h2&gt;Article No Longer Available&lt;/h2&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;
  &lt;small&gt;What is &lt;strong&gt;accessibility&lt;/strong&gt;?&lt;/small&gt;
  &lt;small&gt;Accessibility is a way of making things usable by &lt;em&gt;as many people as possible&lt;/em&gt;, regardless of ability or disability. I like to call it "universal design".&lt;/small&gt; 

&lt;/p&gt;

&lt;p&gt;The article may look daunting at first, and indeed it took me some hours over the course of a few days to read through and digest everything, but it's worth every minute!&lt;/p&gt;

&lt;p&gt;I like this article for taking the enormity of accessibility and condensing it into quick wins applicable to a many different cases. It's a great entry point, providing a list of topics into which you can dig deeper over time.&lt;/p&gt;

&lt;p&gt;Although I had already been making accessibility improvements to my website, I was still able to find some valuable action items for myself. Here are the &lt;strong&gt;top five ways&lt;/strong&gt; I was able to improve my website!&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip 12: One h1 per page
&lt;/h2&gt;

&lt;p&gt;The principle is simple: each page should have one and only one &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; heading!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Of the many pages on your site, the &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; heading tells your visitors exactly where they are.&lt;/li&gt;
&lt;li&gt;Assistive technology such as &lt;strong&gt;screen readers&lt;/strong&gt; rely on this heading to announce that location.&lt;/li&gt;
&lt;li&gt;And usually, this heading demarks the start of the main content, after all the navigation at the top.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A screen reader is capable of reading the content of a site out loud to those who either can't or would rather not read the text. As a feature, they allow people to look at all the headings on a page to jump to where they want to go.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmliikm2ftch7dmog7ek2.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmliikm2ftch7dmog7ek2.png" alt="The page's headings are shown as a list on a menu."&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The headings menu for Mac's VoiceOver tool&lt;/p&gt;



&lt;p&gt;Well, each of the pages on my site use to have &lt;em&gt;two&lt;/em&gt; level one headings: one was the page title, but the other was the &lt;em&gt;website's&lt;/em&gt; title, "Auroratide". And that website title was the same on every single page. That would be pretty annoying to someone using a screen reader!&lt;/p&gt;

&lt;p&gt;The change? Instead of using an &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;, the site's title no longer uses a heading at all and is simply styled to look like one.&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;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"page-title"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Auroratide&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Tip 29: alt attributes
&lt;/h2&gt;

&lt;p&gt;Images are fantastic, but not everyone can see them. Therefore, it is important each image has a suitable &lt;strong&gt;text replacement&lt;/strong&gt; which can either be shown to someone or read aloud by a screen reader. This is called an image's &lt;code&gt;alt&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;Before finding this article, I had already audited every single image on my website to give them suitable text alternatives, but this point is so important I decided to bring it up anyway.&lt;/p&gt;

&lt;p&gt;To write good alt text, imagine you are sharing an article with someone over the phone and need to describe the image to them with words. What you say is generally good alt text! For more on that, here's an article I had recently written:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/auroratide" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F176563%2Fdf2440ff-8bcb-4662-bdd6-c1f1a5c06c0d.png" alt="auroratide"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/auroratide/image-alt-text-the-way-the-spec-intended-it-360i" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Image Alt Text, the Way the Spec Intended It&lt;/h2&gt;
      &lt;h3&gt;Timothy Foster ・ Jul 16 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#html&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#a11y&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Tip 43: Include a skip link to bypass site navigation
&lt;/h2&gt;

&lt;p&gt;Some people prefer to navigate a website entirely with a keyboard, pressing Tab to go from landmark to landmark.&lt;/p&gt;

&lt;p&gt;Usually, pressing Tab on a page for the first time takes you to the very first link, which might be the site's title.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Tab&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the site's title are the navigation links.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Tab&lt;/li&gt;
  &lt;li&gt;Tab&lt;/li&gt;
  &lt;li&gt;Tab&lt;/li&gt;
  &lt;li&gt;Tab&lt;/li&gt;
  &lt;li&gt;Tab&lt;/li&gt;
  &lt;li&gt;Tab&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And after &lt;em&gt;that&lt;/em&gt; is the actual page's content.&lt;/p&gt;

&lt;p&gt;Now imagine hopping from page to page on a site, and &lt;em&gt;every single time&lt;/em&gt; a new page is loaded you have to Tab through the entire navigation just to get to the content. Hence the skip link!&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;skip link&lt;/strong&gt; allows someone to bypass the navigation and get directly to the content. As such, it is generally the first focusable item.&lt;/p&gt;

&lt;p&gt;A basic implementation links to a main element in the document, hiding the link off-screen until it becomes focused:&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;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"skip-link"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Skip to Content&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nc"&gt;.skip-link&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-9999px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;.skip-link&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;small&gt;Here is &lt;a href="https://github.com/Auroratide/auroratide.com/blob/master/src/client/layout/SkipLink/SkipLink.svelte" rel="noopener noreferrer"&gt;my implementation of skip link&lt;/a&gt; on Github.&lt;/small&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Tip 52: Font Size
&lt;/h2&gt;

&lt;p&gt;I remember the early 2000s where websites had tiny Times New Roman fonts. At the time I was also tiny and could read those fonts; nowadays, any time I encounter one of these relics of the past &lt;small&gt;(almost always some .edu site)&lt;/small&gt;, I struggle severely!&lt;/p&gt;

&lt;p&gt;Today, the standard &lt;strong&gt;minimum&lt;/strong&gt; font size is 16px.&lt;/p&gt;

&lt;p&gt;Before reading the accessibility tips, my website had a base font size of 18px, which is actually bigger than the minimum. However, I often make use of &lt;strong&gt;side text&lt;/strong&gt;, stuff tangential to the main content but I feel is worth including. This side text uses a smaller font, which dipped it into a range smaller than 16px. Yikes!&lt;/p&gt;

&lt;p&gt;As a result, I universally bumped &lt;em&gt;all&lt;/em&gt; font sizes up so that now the smallest font possible is 16px, and the usual font is 20px. In fact, the universal increase was necessary since I like the aesthetic of a &lt;em&gt;thin&lt;/em&gt; font, but using a thin font raises the size threshold in order to remain accessible.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;The code change for this was not very bad since I make liberal use of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties" rel="noopener noreferrer"&gt;CSS variables&lt;/a&gt;. Here is a &lt;a href="https://github.com/Auroratide/auroratide.com/commit/11336edde42be011d2eeae18f115953cf1f3250b" rel="noopener noreferrer"&gt;full diff of the font change&lt;/a&gt; for those interested.&lt;/small&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Tip 85: Don't forget the :visited state
&lt;/h2&gt;

&lt;p&gt;You've probably seen this before if you've used the Google search engine: links you have been to are a different color from those that are new.&lt;/p&gt;


&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvfgr1n1vsurgesitr88a.png" alt="One search result is purple and the other is blue."&gt;&lt;p&gt;Don't ask why I was researching multiple time dimensions&lt;/p&gt;



&lt;p&gt;Turns out I rely on this feature &lt;small&gt;(more than I care to admit)&lt;/small&gt; to re-find pages I should have bookmarked! From an accessibility standpoint, differentiating visited links is especially important for those with memory impairment. And thankfully, all it takes is a couple lines of CSS!&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="nd"&gt;:visited&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--skin-text-visited&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;Prior, I had deliberately made all my links the same out of aesthetic preference. However, learning how this simple change could benefit a lot of people convinced me to apply the difference, and honestly I quite like it now.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bonus Tip 101: People are not users
&lt;/h2&gt;

&lt;p&gt;And finally, my favorite tip: Do not call people "users"!&lt;/p&gt;

&lt;p&gt;At least for me, I get very different mental images when I think of users versus people. It's the difference between thinking of the website, or thinking of the &lt;em&gt;face&lt;/em&gt; behind the website. I develop far more empathy for the latter, and ultimately &lt;strong&gt;empathy is at the core of accessibility&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Other 95 Tips
&lt;/h2&gt;

&lt;p&gt;This was just a list of five improvements I was able to make to my website from a list of 101 tips. I highly encourage you to bookmark @inhuofficial 's article to reference when needed!&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;div class="ltag__link__content"&gt;
    &lt;div class="missing"&gt;
      &lt;h2&gt;Article No Longer Available&lt;/h2&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>a11y</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
