Back to Lit

04

packages/lit-dev-content/site/tutorials/content/wc-to-lit/04.md

latest2.9 KB
Original Source

Why Templates

Using innerHTML and template literal strings with no sanitization may cause security issues with script injection. In the past, developers used various workarounds to implement HTML templates, but all of these workarounds had issues.

This is where the <template> element comes in; templates provide truly inert DOM, a highly performant method to clone nodes, and reusable templating.

Using Templates

Next, transition the component to use HTML Templates:

index.html

html
<body>
 <template id="rating-element-template">
   <style>
     :host {
       display: inline-flex;
       align-items: center;
     }
     button {
       background: transparent;
       border: none;
       cursor: pointer;
     }
   </style>
   <button class="thumb_down" >
     <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v2c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z"/></svg>
   </button>
   <span class="rating"></span>
   <button class="thumb_up">
     <svg xmlns="http://www.w3.org/2000/svg" height="24" viewbox="0 0 24 24" width="24"><path d="M1 21h4V9H1v12zm22-11c0-1.1-.9-2-2-2h-6.31l.95-4.57.03-.32c0-.41-.17-.79-.44-1.06L14.17 1 7.59 7.59C7.22 7.95 7 8.45 7 9v10c0 1.1.9 2 2 2h9c.83 0 1.54-.5 1.84-1.22l3.02-7.05c.09-.23.14-.47.14-.73v-2z"/></svg>
   </button>
 </template>

 <rating-element>
   <div>
     This is the light DOM!
   </div>
 </rating-element>
</body>

Here you moved the DOM content into a <template> tag in the main document's DOM. Now refactor the custom element definition:

rating-element.<ts-js></ts-js>

{% switchable-sample %}

ts
connectedCallback() {
  const shadowRoot = this.attachShadow({mode: 'open'});
  const templateContent = document.querySelector<HTMLTemplateElement>('#rating-element-template')!.content;
  const clonedContent = templateContent.cloneNode(true);
  shadowRoot.appendChild(clonedContent);

  this.shadowRoot!.querySelector<HTMLElement>('.rating')!.innerText = `${this.rating}`;
}
js
connectedCallback() {
  const shadowRoot = this.attachShadow({mode: 'open'});
  const templateContent = document.querySelector('#rating-element-template').content;
  const clonedContent = templateContent.cloneNode(true);
  shadowRoot.appendChild(clonedContent);

  this.shadowRoot.querySelector('.rating').innerText = `${this.rating}`;
}

{% endswitchable-sample %}

To use this <template> element:

  1. Query the template.
  2. Get its contents.
  3. Clone those nodes with templateContent.cloneNode
    • The true argument performs a deep clone.
  4. Initialize the dom with the data.

Congratulations, now your web component's DOM is encapsulated, but the DOM is still static. In the next steps, you'll add support for updating the rating.