# Element-defined Content

[Web Components](..) ⟩ [Custom Elements]() ⟩

{% tabs %}
{% tab title="📘 手冊" %}
* Google ⟩ [Element-defined content](https://developers.google.com/web/fundamentals/web-components/customelements#addingmarkup) ⭐️
{% endtab %}

{% tab title="👉 相關" %}
* [HTML Templates](../template)
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Use a <**template**> element to **clone** DOM, instead of setting **shadowRoot.innerHTML**.&#x20;
{% endhint %}

This technique **cuts down** on HTML **parse costs** because the **content of the template** is only **parsed once**, whereas calling **innerHTML** on the **shadowRoot** will parse the HTML for **each instance❗️**

```javascript
// ⭐️ content of <template> is only parsed once❗️
let tmpl = document.createElement('template');

tmpl.innerHTML = `
  <style>:host { ... }</style>
  <b>I'm in shadow dom!</b>
  <slot></slot>
`;

customElements.define('custom-element', class extends HTMLElement {

  constructor() {
  
    // always call super() first in the constructor.
    super(); 

    // Attach a shadow root to the element.
    let root = this.attachShadow({mode: 'open'});
    // ⭐️ clone <template> content
    root.appendChild(tmpl.content.cloneNode(true));
  }
  
});
```

## import \<template> <a href="#import-template" id="import-template"></a>

🤔 下面的程式碼該如何實作呢？（有空再研究）

```markup
<!-- ⭐️ imported from another HTML file -->
<template id="my-element-template">
  <style>
    p { color: green; }
  </style>
  <p>I'm in Shadow DOM. My markup was stamped from a &lt;template&gt;.</p>
</template>

<script>

  // ⭐️ code is inside of an HTML Import (這是什麼❓)
  let tmpl = document.currentScript.ownerDocument.querySelector('#my-element-template');

  customElements.define('my-element-template', class extends HTMLElement {
    constructor() {
      super(); // always call super() first in the constructor.
      let root = this.attachShadow({mode: 'open'});
      root.appendChild(tmpl.content.cloneNode(true));
    }
    ...
  });
</script>
```
