# shadow DOM slots

[browser](https://lochiwei.gitbook.io/web/browser) ⟩ [web components](https://lochiwei.gitbook.io/web/component) ⟩ [implement](https://lochiwei.gitbook.io/web/component/implement) ⟩ [shadow DOM](https://lochiwei.gitbook.io/web/component/shadow-dom) ⟩ slots&#x20;

{% tabs %}
{% tab title="⭐️ 重點" %}
{% hint style="warning" %}

* if those descendants include a <mark style="color:blue;">`<slot>`</mark> element, then the [<mark style="color:yellow;">**regular light DOM children**</mark>](https://lochiwei.gitbook.io/web/component/light-dom) of the [<mark style="color:orange;">**host**</mark>](https://lochiwei.gitbook.io/web/component/shadow-dom) element are displayed <mark style="color:red;">**as if**</mark> they were <mark style="color:yellow;">**children**</mark> of that <mark style="color:blue;">`<slot>`</mark>(they do <mark style="color:red;">**not**</mark> actually become part of the shadow DOM), <mark style="color:red;">**replacing**</mark> any <mark style="color:yellow;">**shadow DOM content**</mark> in the slot.&#x20;
* if [](https://lochiwei.gitbook.io/web/component/shadow-dom "mention") <mark style="color:red;">**does not**</mark> include a <mark style="color:blue;">`<slot>`</mark>, then any <mark style="color:yellow;">**light DOM content**</mark> of the [<mark style="color:orange;">**host**</mark>](https://lochiwei.gitbook.io/web/component/shadow-dom) is <mark style="color:red;">**never displayed**</mark>.&#x20;
* if [](https://lochiwei.gitbook.io/web/component/shadow-dom "mention") has a <mark style="color:blue;">`<slot>`</mark>, but the [<mark style="color:orange;">**shadow host**</mark>](https://lochiwei.gitbook.io/web/component/shadow-dom) has <mark style="color:red;">**no**</mark> <mark style="color:yellow;">**light DOM children**</mark>, then the <mark style="color:yellow;">**shadow DOM content**</mark> of the **slot** is displayed as a default.
  {% endhint %}

{% hint style="info" %}
if [](https://lochiwei.gitbook.io/web/component/shadow-dom "mention") defines <mark style="color:orange;">**more than one**</mark> and <mark style="color:yellow;">**names**</mark> those **slots** with a <mark style="color:blue;">`name`</mark> attribute, then <mark style="color:yellow;">**children**</mark> of the [**shadow host**](https://lochiwei.gitbook.io/web/component/shadow-dom) can specify <mark style="color:yellow;">**which slot**</mark> they would like to appear in by specifying a <mark style="color:blue;">`slot="slotname"`</mark> attribute.
{% endhint %}
{% endtab %}

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

* [ ] JS.info ⟩ [Shadow DOM slots, composition](https://javascript.info/slots-composition)
* [ ] Google ⟩&#x20;
  * [The \<slot> element](https://developers.google.com/web/fundamentals/web-components/shadowdom#slots)
  * [Working with slots in JS](https://developers.google.com/web/fundamentals/web-components/shadowdom#workwithslots)
    {% endtab %}

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

* [The \<slot> element](https://developers.google.com/web/fundamentals/web-components/shadowdom?hl=en#slots)
* [Working with \<slot> in JS](https://developers.google.com/web/fundamentals/web-components/shadowdom?hl=en#workwithslots)
  {% endtab %}

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

* [light, shadow, flattened DOM](https://lochiwei.gitbook.io/web/component/shadow-dom/light-dom)
  {% endtab %}

{% tab title="💈 範例" %}

* [\<custom-menu>](https://lochiwei.gitbook.io/web/component/examples/custom-menu)
* [\<user-card>](https://lochiwei.gitbook.io/web/component/examples/less-than-user-card-greater-than)
* 💾 [named \<slot>](https://replit.com/@pegasusroe/named-lessslotgreater#script.js)
  {% endtab %}
  {% endtabs %}

## Fallback Content

{% hint style="info" %}

* if we put something inside **`<slot>`**(in **shadow DOM**), it becomes the **fallback content**, browser shows it if there’s **no corresponding element** in **light DOM**.\
  👉 See tab 2️⃣ below.
  {% endhint %}

## Default Slot

{% hint style="info" %}

* The **first unnamed** **`<slot>`** in **shadow DOM** is a “**default slot**". It gets **all nodes** from the **light DOM** that **aren’t slotted elsewhere**. 👉 See tab 1️⃣ below.
  {% endhint %}

## Code Example

{% tabs %}
{% tab title="light DOM" %}

```markup
<user-card>
  <!-- ⭐️ light DOM: slotted elements -->
  <!-- ⭐️ only top-level children may have [slot="…"] attribute❗️ -->
  <span slot="username">John Smith</span>
  <span slot="birthday">2001.01.01</span>
</user-card>
```

{% endtab %}

{% tab title="shadow DOM" %}

```javascript
class UserCard extends HTMLElement {

    // connected to document
    connectedCallback() {
        
        // attach shadow root
        const root = this.attachShadow({mode: 'open'});

        // ⭐️ named slots in shadow dom tree
        root.innerHTML = `
            <style>
                ::slotted(*) {
                    border: 1px solid black;
                    padding: 0 4px;
                    display: inline-block;
                    margin: 2px auto;
                    background-color: hsla(60, 80%, 50%, 0.4);
                }
                ::slotted(:hover) {
                    background-color: hsla(90, 80%, 50%, 0.8);
                }
            </style>
            
            <div>Name:
                <slot name="username"></slot>
            </div>
            <div>Birthday:
                <slot name="birthday"></slot>
            </div>
        `;
    }
}

customElements.define('user-card', UserCard);
```

{% endtab %}

{% tab title="flattened DOM" %}

```markup
<user-card>
  #shadow-root
    <div>Name:
      <slot name="username">
        <!-- ⭐️ slotted element is inserted into the slot -->
        <span slot="username">John Smith</span>
      </slot>
    </div>
    <div>Birthday:
      <slot name="birthday">
        <span slot="birthday">01.01.2001</span>
      </slot>
    </div>
</user-card>
```

{% endtab %}

{% tab title="1️⃣" %}

```markup
<script>
customElements.define('user-card', class extends HTMLElement {
  connectedCallback() {
  
    this.attachShadow({mode: 'open'});
    
    // ⭐️ shadow DOM:v2 named slots and 1 default slot
    this.shadowRoot.innerHTML = `
      <div>Name:
        <slot name="username"></slot>
      </div>
      <div>Birthday:
        <slot name="birthday"></slot>
      </div>
      <fieldset>
        <legend>Other information</legend>
        <slot></slot> <!-- ⭐️ default slot -->
      </fieldset>
    `;
  }
  
});
</script>

<user-card>

    <!-- ⭐️ light DOM -->
    
    <!-- ⭐️ elements with [slot="..."] go to named <slot>  -->
    <span slot="username">John Smith</span>
    <span slot="birthday">01.01.2001</span>
    
    <!-- ⭐️ other elements go to default slot -->
    <div>I like to swim.</div>
    <div>...And play volleyball too!</div>
    
</user-card>
```

{% endtab %}

{% tab title="2️⃣" %}

```markup
<div>Name:
  <slot name="username">
    <!-- ⭐️ fallback content -->
    Anonymous
  </slot>
</div>
```

{% endtab %}

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

{% endtab %}
{% endtabs %}

## Named Slots

{% hint style="info" %}

* for eac&#x68;**`<slot name="X">`** in **shadow DOM**, the browser looks fo&#x72;**`[slot="X"]`** in the **light DOM** and insert it into the slot, the result is called **flattened DOM**.\
  👉 See code in "shadow DOM", "flattened DOM" tabs above.<br>
* if there are **multiple elements** in **light DOM** with the **same`[slot="X"]`**, they are **appended** into the sam&#x65;**`<slot name="X">`** (in **shadow DOM**), one after another.
  {% endhint %}

## Flattened DOM

{% hint style="warning" %}
the **flattened DOM** exists only for **rendering** and **event-handling** purposes. It’s kind of “virtual”. That’s how things are shown. But the **nodes** in the document are actually **not** **moved** around! 👉 See "flattened DOM" tab above.

The process of rendering [slotted elements](#slotted-elements) inside their **slots** is called “**composition**”.
{% endhint %}
