Search code examples
htmlweb-componentshadow-domcustom-elementcontent-tag

Using the <content> tag in a shadow DOM


I'm trying to use the shadow DOM without any framework that abstracts it, mostly in order to learn its intricacies. I am using the webcomponents.js polyfills, so it works cross-browser.

I've managed to create a custom element, and set its shadow DOM, but for some reason the <content></content> tag isn't transcluding the expected content.

I expect this example to render as

Shadow DOM
Hello world
More Shadow

But it renders as

Shadow DOM
More Shadow

What am I missing here?

<script src="webcomponents-lite.min.js"></script>

<test-component>
    <div>Hello world</div>
</test-component>

<template id="test-component">
    <div>Shadow DOM</div>
    <content></content>
    <div>More shadow</div>
</template>

<script>
    class TestComponent extends HTMLElement {
        constructor() {
            super();

            var shadow = super.attachShadow({ mode: 'open' });

            var template = document.getElementById('test-component');
            var clone = document.importNode(template.content, true);
            shadow.appendChild(clone);
        }
    }

    customElements.define('test-component', TestComponent);
</script>

(The example is complete, and can be run as an entire HTML file, provided you have webcomponents-lite.min.js available, or can be run without the .js file in supported browsers)


Solution

  • As noted in a comment above, you need to use the slot element and slot attribute instead. Here’s exactly the same code as above, but implemented using the slot element and attribute:

    <test-component>
        <div slot=middle>Hello world</div>
    </test-component>
    
    <template id="test-component">
        <div>Shadow DOM</div>
        <slot name=middle></slot>
        <div>More shadow</div>
    </template>
    
    <script>
        class TestComponent extends HTMLElement {
            constructor() {
                super();
    
                var shadow = super.attachShadow({ mode: 'open' });
    
                var template = document.getElementById('test-component');
                var clone = document.importNode(template.content, true);
                shadow.appendChild(clone);
            }
        }
    
        customElements.define('test-component', TestComponent);
    </script>