# \`slotchange\` event

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

* JS.info ⟩ [Updating slots](https://javascript.info/slots-composition#updating-slots)
* Google ⟩ [Working with slots in JS](https://developers.google.com/web/fundamentals/web-components/shadowdom#workwithslots)
  {% endtab %}

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

* [Shadow DOM Events](/web/component/shadow-dom/events.md)
  {% endtab %}

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

* MDN ⟩ [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver)
* MDN ⟩&#x20;
  * HTMLSlotElement ⟩ [assignedNodes()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLSlotElement/assignedNodes): Node\[ ]
  * Element ⟩ [assignedSlot](https://developer.mozilla.org/en-US/docs/Web/API/Element/assignedSlot): HTMLSlotElement - slot that element is assigned to.
    {% endtab %}
    {% endtabs %}

{% hint style="info" %}
**Note:** "**slotchange"** does **not** fire when an instance of the component is first **initialized**.
{% endhint %}

The **`slotchange`** event fires when a slot's [distributed nodes](/web/component/template/slot/slotted-elements.md) changes. For example, if the user adds/removes children from the **light DOM**.

```javascript
const slot = this.shadowRoot.querySelector('#slot');

// ⭐️ `slotchange` event listener
slot.addEventListener('slotchange', e => {
    console.log('light dom children changed!');
});
```

{% hint style="info" %}
To monitor **other types** of changes to **light DOM**, you can setup a [`MutationObserver`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) in your **element's constructor**.
{% endhint %}

## example

:floppy\_disk: [replit](https://replit.com/@pegasusroe/slotchange-event#CustomMenu.js)

{% tabs %}
{% tab title="CustomMenu.js" %}

```javascript
const { log } = console;

// CustomMenu
class CustomMenu extends HTMLElement {

    // connected to doc
    connectedCallback() {

        // shadow root
        const root = this.attachShadow({mode: 'open'});

        // shadow dom tree (with named slots ⭐️)
        root.innerHTML = `
        <div class="container">
            <slot name="title"></slot>
            <ul><slot name="item"></slot></ul>
        </div>
        `;

        // container (div.container)
        this.container = this.shadowRoot.firstElementChild;

        // ⭐️ shadowRoot can't have event handlers, 
        //    so using the first child.
        this.container.addEventListener('slotchange', e => {
            let slot = e.target;                // changed slot (in shadow DOM)
            log("slotchange: " + slot.name)     // ⭐️ slot name
            if(slot.name === 'item'){
                // ⭐️ slot.assignedElements() is of type `Element[]`
                let items = slot.assignedElements().map(elem => elem.textContent);
                log('items:', items);
            }
        });

    }// end: connectedCallback()

}// end: CustomMenu

// register <custom-menu> tag
customElements.define('custom-menu', CustomMenu);
```

{% endtab %}

{% tab title="script.js" %}

```javascript
// ⭐️ elem.$('div')
Element.prototype.$ = function(selector){
    return this.querySelector(selector);
};

// add 3 new menu items every sec
['Lollipop', 'Apple', 'Milk Shake'].forEach((text, i) => {
    setTimeout(() => {
        customMenu.insertAdjacentHTML('beforeEnd', 
            `<li slot="item">${text}</li>`
        )
    }, 1000 + i * 1000);
})


// change menu title in 4s
setTimeout(() => {
    customMenu.$('[slot="title"]').innerHTML = "New menu ⭐️";
}, 4000);
```

{% endtab %}

{% tab title="html" %}

```markup
<custom-menu id="customMenu">
	<!-- ⭐️ light dom: slotted elements -->
	<span slot="title">Candy menu</span>
</custom-menu>
```

{% endtab %}

{% tab title="⭐️ `slotchange` events" %}

| slot name | notes                                                                    |
| --------- | ------------------------------------------------------------------------ |
| title     | **`<span slot="title">Candy menu</span>`** inserted into **title slot**. |
| item      | new **`<li slot="item">`** tag inserted into **item slot**.              |
| item      | new **`<li slot="item">`** tag inserted into **item slot**.              |
| item      | new **`<li slot="item">`** tag inserted into **item slot**.              |

{% hint style="danger" %}
there's **NO`slotchange`** event after 4 sec (on **modifying the content** of a **slotted element**). &#x20;
{% endhint %}

{% hint style="info" %}
If we’d like to **track** internal **modifications** of **light DOM** from JavaScript, use: [MutationObserver](https://javascript.info/mutation-observer).
{% endhint %}
{% 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/slot/slotchange.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.
