# \<template>

[web](/web/master.md) ⟩ [component](/web/component.md) ⟩ \<template>

{% hint style="info" %}
🚧
{% endhint %}

{% tabs %}
{% tab title="👥 相關" %}

* [Custom Events](/web/browser/event/custom.md) ⟩ [Element-defined Content](/web/component/custom-element/content.md)
* [DOM hierarchy](/web/browser/dom/hierarchy.md)
* [content](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement/content) of <mark style="color:purple;">**`<template>`**</mark> is a [DocumentFragment](/web/browser/dom/type/documentfragment.md).
* 可將 <mark style="color:purple;">**`<template>`**</mark> 放在[靜態屬性](/web/js/val/class/member/static.md)中，詳情： :point\_right: [init static property](/web/js/val/class/member/static/init.md)
  {% endtab %}

{% tab title="⭐️ 重點" %}
{% hint style="info" %}
[\<template>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) tags (and their <mark style="color:yellow;">**children**</mark>)：&#x20;

* <mark style="color:red;">**never**</mark> <mark style="color:yellow;">**rendered**</mark> by web browser.
* only useful on web pages that use <mark style="color:yellow;">**JavaScript**</mark>.
* [template.content](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement/content) is a [DocumentFragment](/web/browser/dom/type/documentfragment.md).
* can be **cloned** by template.[content](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement/content).[cloneNode()](https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode).&#x20;
  {% endhint %}

{% hint style="warning" %}

* when cloning/inserting [template.content](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement/content) into document, the [fragment](/web/browser/dom/type/documentfragment.md) itself will <mark style="color:red;">**not**</mark> be inserted, but its <mark style="color:yellow;">**children**</mark> will.
  {% endhint %}

{% hint style="info" %}
Use a <**template**> element to **clone** DOM, instead of setting **shadowRoot.innerHTML**. \
👉 [Custom Elements](/web/component/custom-element.md) ⟩ [Element-defined Content](/web/component/custom-element/content.md)
{% endhint %}
{% endtab %}

{% tab title="📗 參考" %}

* [ ] [\<template> element](https://javascript.info/template-element) - js.info
  {% endtab %}

{% tab title="📘 手冊" %}

* 📘 [Using templates and slots](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots)
  * [Using templates with web components](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_templates_and_slots#using_templates_with_web_components)
* [\<template>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template)
* [Node](/web/browser/dom/type/node.md) ⟩ [.cloneNode()](https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode)
* 📘 [DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment)
* [HTMLTemplateElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement)
  * .[content](https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement/content) ([DocumentFragment](https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment))
    {% endtab %}
    {% endtabs %}

## HTML templates examples

{% tabs %}
{% tab title="1️⃣" %}
:floppy\_disk: [replit.com](https://replit.com/@pegasusroe/web-component-error-message#script.js)

{% hint style="info" %}

* can put <mark style="color:blue;">`<style>`</mark> and <mark style="color:blue;">`<script>`</mark> into <mark style="color:blue;">`<template>`</mark> as well.
  {% endhint %}

```markup
<!-- styles and scripts in template -->
<template>

  <style>
    p { font-weight: bold; }
  </style>
  
  <script>
    alert("Hello");
  </script>
  
</template>
```

{% endtab %}

{% tab title="2️⃣" %}
{% hint style="info" %}

* content **becomes live** (styles apply, scripts run etc) when **inserted** into **document**.
  {% endhint %}

```markup
<!-- template -->
<template id="tmpl">
  <script>
    console.log("Hello");
  </script>
  <div class="message">Hello, world!</div>
</template>

<!-- script -->
<script>

  let div = document.createElement('div');

  // ⭐️ clone template content
  //    tmpl            : HTMLTemplateElement
  //    tmpl.content    : DocumentFragment
  //    node.cloneNode(): Node (return type)
  div.append(tmpl.content.cloneNode(true));

  // ⭐️ inserted into document
  // ⭐️ now script (from <template>) runs
  document.body.append(div);    
  
</script>
```

{% endtab %}

{% tab title="3️⃣" %}
{% hint style="info" %}

* we can use `<template>` to **populate** [shadow root](/web/component/shadow-dom/shadow-root.md).&#x20;
  {% endhint %}

📁 script.js  👉 [replit](https://replit.com/@pegasusroe/use-template-to-populate-shadow-root#script.js)

```javascript
div.onclick = function() {

    // attach shadow root to <div> (shadow host)
    let root = div.attachShadow({mode: 'open'});

    // clone template content (<style>, <p>)
    let clonedContent = tmpl.content.cloneNode(true);

    // append to shadow root
    // ⭐️ 注意：light DOM (text node: "Click me") 被 shadow DOM 取代了❗️
    root.append(clonedContent);

    let p = root.$('#message');
    p.innerHTML = "Hello from the shadows❗️";
}; 
```

📁 index.html

```markup
<!-- ⭐️ template -->
<template id="tmpl">
	<style>
		p {
			font-weight: bold;
                margin: 0 auto;
		}
	</style>
	<p id="message"></p>
</template>

<!-- shadow host -->
<div id="div">Click me❗️</div>

<!-- scripts -->
<script src="helpers.js"></script>
<script src="script.js"></script>
```

👉 [helpers.js](/web/browser/dom/querying-elements/dom.md)
{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="HTML" %}

```markup
<!-- web component -->
<my-component>
  a "none" error message
</my-component>

<my-component kind="warning">
  this is a warning
</my-component>

<my-component kind="error">
  this is an error message
</my-component>
```

{% endtab %}

{% tab title="JS" %}

```javascript
// ⭐️ 1. custom web component
class MyComponent extends HTMLElement {

    // constructor
    constructor() {

        // tell HTMLElement to initialize itself.
        super();

    }

    // choose which template to use
    connectedCallback() {

        // create <div> elements
        this.templates = document.createElement('div');
        this.container = document.createElement('div');

        // ⭐️ add a shadow DOM to component
        //    to activate/deactivate templates
        this.root = this.attachShadow({mode: 'open'});
        this.root.appendChild(this.templates); 
        this.root.appendChild(this.container);

        // fill in templates
        this.templates.innerHTML = MyComponent.template(); 
        
        // choose which template to use
        const kind = this.getAttribute(`kind`) || `none`;
        const template = this.templates.querySelector(`template.${kind}-type`); 
        
        if (template) {
            const clone = template.content.cloneNode(true);
            this.container.innerHTML = '';
            this.container.appendChild(clone); 
        }

    }

    // template HTML
    static template() {

        // 3 templates
        // - template.warning-type
        // - template.error-type
        // - template.none-type
        return ` 
            <template class="warning-type">
                <style> 
                    .warning { 
                        background-color: yellow; 
                        padding: 15px; 
                        color: red; 
                    } 
                </style>

                <div class="warning">
                    <slot>Error component<slot> 
                </div> 
            </template>

            <template class="error-type">
                <style>
                    .error { 
                        background-color: red; 
                        padding: 15px; 
                        color: yellow; 
                    }
                </style>

                <div class="error">
                    <slot>Error component<slot> 
                </div> 
            </template>

            <template class="none-type">
                <style> 
                    .none { 
                        background-color: gray; 
                        padding: 15px; 
                        color: #eee; 
                    } 
                </style>

                <div class="none">
                    <slot>Error component<slot> 
                </div> 
            </template>
        `;
    }
} 

// ⭐️ 2. custom tag <my-component>
// ⭐️⭐️ custom element names must contain a "hyphen".
customElements.define('my-component', MyComponent);
```

{% endtab %}

{% tab title="codepen" %}
{% embed url="<https://codepen.io/lochiwei/pen/yLXOrVm>" %}

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lochiwei.gitbook.io/web/component/template.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
