yaakai.to

🖊

Declarative Shadow DOM

Baseline 2024 で追加された、これまで JavaScript からしか生成できなかった Shadow DOM を HTML で定義できるようになる機能です。これによって、Web Components をサーバーサイドでのレンダリングに対応させることができます。

次のような HTML として記述することで Shadow DOM が生成されます。(動作サンプル)

<my-custom-element data-count="12345">
    <template shadowrootmode="open">
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            .container {
                display: flex;
                gap: 8px;
            }
            .counter {
                font-weight: bold;
            }
            .increment, .decrement {
                width: 20px;
                cursor: pointer;
            }
        </style>
        <div class="container">
        <p class="counter">12345</p>
        <button class="increment">+</button>
        <button class="decrement">-</button>
        </div>
    </template>
</my-custom-element>

同名で customElements.define された HTMLElement があれば、自動的にアップデートされ、 constructorconnectedCallback で Hydration を行うことができます。

class MyCustomElement extends HTMLElement {
    connectedCallback() {
        let count = parseInt(this.getAttribute('data-count'))
        this.shadowRoot.querySelector('.increment').addEventListener('click', () => {
            this.shadowRoot.querySelector('.counter').textContent = String(++count)
        })
        this.shadowRoot.querySelector('.decrement').addEventListener('click', () => {
            this.shadowRoot.querySelector('.counter').textContent = String(--count)
        })
    }
}
customElements.define("my-custom-element", MyCustomElement);

Declarative Shadow DOM の形で JavaScript から要素を追加する場合、 $el.innerHTML = htmlString ではセキュリティ上の理由から実行が行われず、代わりに setHTMLUnsafeparseHTMLUnsafe を利用する必要があります。

Refs