A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.md 11KB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. title: Understanding Kristofer Joseph's Single File Web Component
  2. url: https://til.simonwillison.net/web-components/understanding-single-file-web-component
  3. hash_url: 8016f83f512107dd26e5780b08ea7305
  4. <p><a href="https://twitter.com/brianleroux/status/1453472609518034944" rel="nofollow">Via Brian LeRoux</a> I found <a href="https://gist.github.com/kristoferjoseph/c4e47389ae0f0447db175b914e471628">single-file-web-component.html</a> by Kristofer Joseph. It's really clever! It demonstrates how to build a <code>&lt;hello-world&gt;&lt;/hello-world&gt;</code> custom Web Component in a single HTML file, using some neat tricks.</p>
  5. <p>For my own education I spent some time picking it apart and built my own annotated version of the code showing what I learned.</p>
  6. <p>Justin Fagnani <a href="https://twitter.com/justinfagnani/status/1453531485240102916" rel="nofollow">provided useful feedback</a> on this on Twitter.</p>
  7. <div class="highlight highlight-text-html-basic"><pre><span class="pl-c1">&lt;!DOCTYPE html<span class="pl-kos">&gt;</span></span>
  8. <span class="pl-kos">&lt;</span><span class="pl-ent">html</span> <span class="pl-c1">lang</span>="<span class="pl-s">en</span>"<span class="pl-kos">&gt;</span>
  9. <span class="pl-kos">&lt;</span><span class="pl-ent">head</span><span class="pl-kos">&gt;</span>
  10. <span class="pl-kos">&lt;</span><span class="pl-ent">meta</span> <span class="pl-c1">charset</span>="<span class="pl-s">UTF-8</span>" /&gt;
  11. <span class="pl-kos">&lt;</span><span class="pl-ent">title</span><span class="pl-kos">&gt;</span>Single File Web Component<span class="pl-kos">&lt;/</span><span class="pl-ent">title</span><span class="pl-kos">&gt;</span>
  12. <span class="pl-kos">&lt;</span><span class="pl-ent">style</span><span class="pl-kos">&gt;</span>
  13. <span class="pl-ent">body</span> {
  14. <span class="pl-c1">background-color</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>eee</span>;
  15. <span class="pl-c1">font-family</span><span class="pl-kos">:</span> Helvetica<span class="pl-kos">,</span> sans-serif;
  16. }
  17. <span class="pl-ent">h1</span> {
  18. <span class="pl-c1">color</span><span class="pl-kos">:</span> blue;
  19. <span class="pl-c1">background-color</span><span class="pl-kos">:</span> pink;
  20. }
  21. <span class="pl-kos">&lt;/</span><span class="pl-ent">style</span><span class="pl-kos">&gt;</span>
  22. <span class="pl-kos">&lt;/</span><span class="pl-ent">head</span><span class="pl-kos">&gt;</span>
  23. <span class="pl-kos">&lt;</span><span class="pl-ent">body</span><span class="pl-kos">&gt;</span>
  24. <span class="pl-kos">&lt;</span><span class="pl-ent">template</span> <span class="pl-c1">id</span>="<span class="pl-s">single-file</span>"<span class="pl-kos">&gt;</span>
  25. <span class="pl-kos">&lt;</span><span class="pl-ent">style</span><span class="pl-kos">&gt;</span>
  26. <span class="pl-c">/*</span>
  27. <span class="pl-c"> These styles affect only content inside the shadow DOM.</span>
  28. <span class="pl-c"></span>
  29. <span class="pl-c"> Styles in the outside document mostly do not affect stuff</span>
  30. <span class="pl-c"> here, but there are some exceptions: font-family affects</span>
  31. <span class="pl-c"> this &lt;h1&gt; for example. I don't understand the rules here.</span>
  32. <span class="pl-c"> */</span>
  33. <span class="pl-ent">h1</span> {
  34. <span class="pl-c1">color</span><span class="pl-kos">:</span> red;
  35. }
  36. <span class="pl-kos">&lt;/</span><span class="pl-ent">style</span><span class="pl-kos">&gt;</span>
  37. <span class="pl-kos">&lt;</span><span class="pl-ent">h1</span><span class="pl-kos">&gt;</span>Hello world (web component)<span class="pl-kos">&lt;/</span><span class="pl-ent">h1</span><span class="pl-kos">&gt;</span>
  38. <span class="pl-c">&lt;!--</span>
  39. <span class="pl-c"> This code still works if you remove the type="module" parameter.</span>
  40. <span class="pl-c"></span>
  41. <span class="pl-c"> Using that parameter enables features such as 'import ... from'</span>
  42. <span class="pl-c"></span>
  43. <span class="pl-c"> More importantly it stops variables inside the script tag from</span>
  44. <span class="pl-c"> leaking out to the global scope - if you remove type="module"</span>
  45. <span class="pl-c"> from here then the HelloWorld class becomes visible.</span>
  46. <span class="pl-c"> --&gt;</span>
  47. <span class="pl-kos">&lt;</span><span class="pl-ent">script</span> <span class="pl-c1">type</span>="<span class="pl-s">module</span>"<span class="pl-kos">&gt;</span>
  48. <span class="pl-k">class</span> <span class="pl-v">HelloWorld</span> <span class="pl-k">extends</span> <span class="pl-v">HTMLElement</span> <span class="pl-kos">{</span>
  49. <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  50. <span class="pl-c">/*</span>
  51. <span class="pl-c"> If you remove the call to super() here Firefox shows an error:</span>
  52. <span class="pl-c"> "Uncaught ReferenceError: must call super constructor before</span>
  53. <span class="pl-c"> using 'this' in derived class constructor'"</span>
  54. <span class="pl-c"> */</span>
  55. <span class="pl-smi">super</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  56. <span class="pl-k">const</span> <span class="pl-s1">template</span> <span class="pl-c1">=</span> <span class="pl-smi">document</span><span class="pl-kos">.</span><span class="pl-en">getElementById</span><span class="pl-kos">(</span><span class="pl-s">"single-file"</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  57. <span class="pl-c">/*</span>
  58. <span class="pl-c"> mode: 'open' means you are allowed to access</span>
  59. <span class="pl-c"> document.querySelector('hello-world').shadowRoot to get</span>
  60. <span class="pl-c"> at the DOM inside. Set to 'closed' and the .shadowRoot</span>
  61. <span class="pl-c"> property will return null.</span>
  62. <span class="pl-c"> */</span>
  63. <span class="pl-smi">this</span><span class="pl-kos">.</span><span class="pl-en">attachShadow</span><span class="pl-kos">(</span><span class="pl-kos">{</span> <span class="pl-c1">mode</span>: <span class="pl-s">"open"</span> <span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-en">appendChild</span><span class="pl-kos">(</span>
  64. <span class="pl-s1">template</span><span class="pl-kos">.</span><span class="pl-c1">content</span><span class="pl-kos">.</span><span class="pl-en">cloneNode</span><span class="pl-kos">(</span><span class="pl-c1">true</span><span class="pl-kos">)</span>
  65. <span class="pl-kos">)</span><span class="pl-kos">;</span>
  66. <span class="pl-c">/* </span>
  67. <span class="pl-c"> template.content is a 'DocumentFragment' array.</span>
  68. <span class="pl-c"></span>
  69. <span class="pl-c"> template.content.cloneNode() without the true performs</span>
  70. <span class="pl-c"> a shallow clone, which provides a empty DocumentFragment</span>
  71. <span class="pl-c"> array.</span>
  72. <span class="pl-c"></span>
  73. <span class="pl-c"> template.content.cloneNode(true) provides one with 6 items</span>
  74. <span class="pl-c"> */</span>
  75. <span class="pl-kos">}</span>
  76. <span class="pl-en">connectedCallback</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
  77. <span class="pl-c">// https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks</span>
  78. <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">"Why hello there 👋"</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  79. <span class="pl-kos">}</span>
  80. <span class="pl-kos">}</span>
  81. <span class="pl-s1">customElements</span><span class="pl-kos">.</span><span class="pl-en">define</span><span class="pl-kos">(</span><span class="pl-s">"hello-world"</span><span class="pl-kos">,</span> <span class="pl-v">HelloWorld</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  82. <span class="pl-kos">&lt;/</span><span class="pl-ent">script</span><span class="pl-kos">&gt;</span>
  83. <span class="pl-kos">&lt;/</span><span class="pl-ent">template</span><span class="pl-kos">&gt;</span>
  84. <span class="pl-kos">&lt;</span><span class="pl-ent">h1</span><span class="pl-kos">&gt;</span>This is not a web component<span class="pl-kos">&lt;/</span><span class="pl-ent">h1</span><span class="pl-kos">&gt;</span>
  85. <span class="pl-kos">&lt;</span><span class="pl-ent">hello-world</span><span class="pl-kos">&gt;</span><span class="pl-kos">&lt;/</span><span class="pl-ent">hello-world</span><span class="pl-kos">&gt;</span>
  86. <span class="pl-kos">&lt;</span><span class="pl-ent">script</span><span class="pl-kos">&gt;</span>
  87. <span class="pl-k">const</span> <span class="pl-s1">sf</span> <span class="pl-c1">=</span> <span class="pl-smi">document</span><span class="pl-kos">.</span><span class="pl-en">getElementById</span><span class="pl-kos">(</span><span class="pl-s">"single-file"</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  88. <span class="pl-c">/*</span>
  89. <span class="pl-c"> Before executing this line, sf.content.lastElementChild</span>
  90. <span class="pl-c"> is the &lt;script type="module"&gt; element hidden away inside</span>
  91. <span class="pl-c"> the &lt;template&gt; - we remove it from the template here and</span>
  92. <span class="pl-c"> append it to the document.body, causing it to execute in</span>
  93. <span class="pl-c"> the main document and activate the &lt;hello-world&gt; tag.</span>
  94. <span class="pl-c"> */</span>
  95. <span class="pl-smi">document</span><span class="pl-kos">.</span><span class="pl-c1">body</span><span class="pl-kos">.</span><span class="pl-en">appendChild</span><span class="pl-kos">(</span><span class="pl-s1">sf</span><span class="pl-kos">.</span><span class="pl-c1">content</span><span class="pl-kos">.</span><span class="pl-c1">lastElementChild</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  96. <span class="pl-kos">&lt;/</span><span class="pl-ent">script</span><span class="pl-kos">&gt;</span>
  97. <span class="pl-kos">&lt;/</span><span class="pl-ent">body</span><span class="pl-kos">&gt;</span>
  98. <span class="pl-kos">&lt;/</span><span class="pl-ent">html</span><span class="pl-kos">&gt;</span></pre></div>
  99. <p class="created">Created 2021-10-27T17:33:08-07:00, updated 2021-10-27T19:48:23-07:00 · <a href="https://github.com/simonw/til/commits/main/web-components/understanding-single-file-web-component.md">History</a> · <a href="https://github.com/simonw/til/blob/main/web-components/understanding-single-file-web-component.md">Edit</a></p>