|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- title: Understanding Kristofer Joseph's Single File Web Component
- url: https://til.simonwillison.net/web-components/understanding-single-file-web-component
- hash_url: 8016f83f512107dd26e5780b08ea7305
-
- <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><hello-world></hello-world></code> custom Web Component in a single HTML file, using some neat tricks.</p>
- <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>
- <p>Justin Fagnani <a href="https://twitter.com/justinfagnani/status/1453531485240102916" rel="nofollow">provided useful feedback</a> on this on Twitter.</p>
- <div class="highlight highlight-text-html-basic"><pre><span class="pl-c1"><!DOCTYPE html<span class="pl-kos">></span></span>
- <span class="pl-kos"><</span><span class="pl-ent">html</span> <span class="pl-c1">lang</span>="<span class="pl-s">en</span>"<span class="pl-kos">></span>
- <span class="pl-kos"><</span><span class="pl-ent">head</span><span class="pl-kos">></span>
- <span class="pl-kos"><</span><span class="pl-ent">meta</span> <span class="pl-c1">charset</span>="<span class="pl-s">UTF-8</span>" />
- <span class="pl-kos"><</span><span class="pl-ent">title</span><span class="pl-kos">></span>Single File Web Component<span class="pl-kos"></</span><span class="pl-ent">title</span><span class="pl-kos">></span>
- <span class="pl-kos"><</span><span class="pl-ent">style</span><span class="pl-kos">></span>
- <span class="pl-ent">body</span> {
- <span class="pl-c1">background-color</span><span class="pl-kos">:</span> <span class="pl-pds"><span class="pl-kos">#</span>eee</span>;
- <span class="pl-c1">font-family</span><span class="pl-kos">:</span> Helvetica<span class="pl-kos">,</span> sans-serif;
- }
- <span class="pl-ent">h1</span> {
- <span class="pl-c1">color</span><span class="pl-kos">:</span> blue;
- <span class="pl-c1">background-color</span><span class="pl-kos">:</span> pink;
- }
- <span class="pl-kos"></</span><span class="pl-ent">style</span><span class="pl-kos">></span>
- <span class="pl-kos"></</span><span class="pl-ent">head</span><span class="pl-kos">></span>
- <span class="pl-kos"><</span><span class="pl-ent">body</span><span class="pl-kos">></span>
- <span class="pl-kos"><</span><span class="pl-ent">template</span> <span class="pl-c1">id</span>="<span class="pl-s">single-file</span>"<span class="pl-kos">></span>
- <span class="pl-kos"><</span><span class="pl-ent">style</span><span class="pl-kos">></span>
- <span class="pl-c">/*</span>
- <span class="pl-c"> These styles affect only content inside the shadow DOM.</span>
- <span class="pl-c"></span>
- <span class="pl-c"> Styles in the outside document mostly do not affect stuff</span>
- <span class="pl-c"> here, but there are some exceptions: font-family affects</span>
- <span class="pl-c"> this <h1> for example. I don't understand the rules here.</span>
- <span class="pl-c"> */</span>
- <span class="pl-ent">h1</span> {
- <span class="pl-c1">color</span><span class="pl-kos">:</span> red;
- }
- <span class="pl-kos"></</span><span class="pl-ent">style</span><span class="pl-kos">></span>
-
- <span class="pl-kos"><</span><span class="pl-ent">h1</span><span class="pl-kos">></span>Hello world (web component)<span class="pl-kos"></</span><span class="pl-ent">h1</span><span class="pl-kos">></span>
- <span class="pl-c"><!--</span>
- <span class="pl-c"> This code still works if you remove the type="module" parameter.</span>
- <span class="pl-c"></span>
- <span class="pl-c"> Using that parameter enables features such as 'import ... from'</span>
- <span class="pl-c"></span>
- <span class="pl-c"> More importantly it stops variables inside the script tag from</span>
- <span class="pl-c"> leaking out to the global scope - if you remove type="module"</span>
- <span class="pl-c"> from here then the HelloWorld class becomes visible.</span>
- <span class="pl-c"> --></span>
- <span class="pl-kos"><</span><span class="pl-ent">script</span> <span class="pl-c1">type</span>="<span class="pl-s">module</span>"<span class="pl-kos">></span>
- <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>
- <span class="pl-en">constructor</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
- <span class="pl-c">/*</span>
- <span class="pl-c"> If you remove the call to super() here Firefox shows an error:</span>
- <span class="pl-c"> "Uncaught ReferenceError: must call super constructor before</span>
- <span class="pl-c"> using 'this' in derived class constructor'"</span>
- <span class="pl-c"> */</span>
- <span class="pl-smi">super</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
- <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>
- <span class="pl-c">/*</span>
- <span class="pl-c"> mode: 'open' means you are allowed to access</span>
- <span class="pl-c"> document.querySelector('hello-world').shadowRoot to get</span>
- <span class="pl-c"> at the DOM inside. Set to 'closed' and the .shadowRoot</span>
- <span class="pl-c"> property will return null.</span>
- <span class="pl-c"> */</span>
- <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>
- <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>
- <span class="pl-kos">)</span><span class="pl-kos">;</span>
- <span class="pl-c">/* </span>
- <span class="pl-c"> template.content is a 'DocumentFragment' array.</span>
- <span class="pl-c"></span>
- <span class="pl-c"> template.content.cloneNode() without the true performs</span>
- <span class="pl-c"> a shallow clone, which provides a empty DocumentFragment</span>
- <span class="pl-c"> array.</span>
- <span class="pl-c"></span>
- <span class="pl-c"> template.content.cloneNode(true) provides one with 6 items</span>
- <span class="pl-c"> */</span>
- <span class="pl-kos">}</span>
- <span class="pl-en">connectedCallback</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
- <span class="pl-c">// https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks</span>
- <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>
- <span class="pl-kos">}</span>
- <span class="pl-kos">}</span>
- <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>
- <span class="pl-kos"></</span><span class="pl-ent">script</span><span class="pl-kos">></span>
- <span class="pl-kos"></</span><span class="pl-ent">template</span><span class="pl-kos">></span>
-
- <span class="pl-kos"><</span><span class="pl-ent">h1</span><span class="pl-kos">></span>This is not a web component<span class="pl-kos"></</span><span class="pl-ent">h1</span><span class="pl-kos">></span>
-
- <span class="pl-kos"><</span><span class="pl-ent">hello-world</span><span class="pl-kos">></span><span class="pl-kos"></</span><span class="pl-ent">hello-world</span><span class="pl-kos">></span>
-
- <span class="pl-kos"><</span><span class="pl-ent">script</span><span class="pl-kos">></span>
- <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>
- <span class="pl-c">/*</span>
- <span class="pl-c"> Before executing this line, sf.content.lastElementChild</span>
- <span class="pl-c"> is the <script type="module"> element hidden away inside</span>
- <span class="pl-c"> the <template> - we remove it from the template here and</span>
- <span class="pl-c"> append it to the document.body, causing it to execute in</span>
- <span class="pl-c"> the main document and activate the <hello-world> tag.</span>
- <span class="pl-c"> */</span>
- <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>
- <span class="pl-kos"></</span><span class="pl-ent">script</span><span class="pl-kos">></span>
- <span class="pl-kos"></</span><span class="pl-ent">body</span><span class="pl-kos">></span>
- <span class="pl-kos"></</span><span class="pl-ent">html</span><span class="pl-kos">></span></pre></div>
-
-
- <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>
|