javascripthtmlweb-componentshadow-domslot

How to programmatically create a slot and slot a HTMLElement into it?


I'd like to, without using HTML, create a slot and slot an element into it. I tried the following and a few variations but no luck. What am I doing wrong? Why is slot.assignedNodes() returning an empty array after I assigned the element?

const element = document.createElement('div');
const slot = document.createElement('slot');
const slotted = document.createElement('span');

document.body.append(element);
element.attachShadow({ mode: 'open', slotAssignment: 'manual'});

element.shadowRoot.append(slot);
element.shadowRoot.append(slotted);

slot.assign(slotted);
console.log(slot.assignedNodes());


Solution

  • Your problem is here:

    element.shadowRoot.append(slot);
    element.shadowRoot.append(slotted);
    

    You are assigning slotted to the same shadowDOM the <slot> is in.
    It should go to lightDOM with: element.append(slotted)


    I rewrote your code so (I hope) its clearer

    const DIV = document.createElement('DIV');
    DIV.attachShadow({ mode: 'open', slotAssignment: 'manual'});
    
    const SLOT = document.createElement('SLOT');
    DIV.shadowRoot.append( SLOT ); // Create SLOT in SHADOWDOM
    
    document.body.append( DIV );
    
    const SPAN = document.createElement('SPAN');
    SPAN.innerHTML = "I AM SLOTTED";
    
    DIV.append(SPAN); // put me in LIGHTDOM!
    
    SLOT.assign( SPAN ); // only works because of slotAssignment:"manual" !!
    
    console.log(SLOT.assignedNodes());

    Without slotAssignment:"manual" you do not need SLOT.assign(SPAN) because lightDOM content will automagically be slotted to the default unnamed <slot>

    With standard slot behavior

    const DIV = document.createElement('DIV');
    DIV.attachShadow({ mode: 'open'});
    
    const SLOT1 = document.createElement('SLOT'); // default slot
    const SLOT2 = document.createElement('SLOT'); // slot name='title' !
    SLOT2.name = "title";
    DIV.shadowRoot.append( SLOT1 , SLOT2 ); // Create SLOTs in SHADOWDOM
    
    document.body.append( DIV );
    
    const SPAN = document.createElement('SPAN');
    SPAN.slot = "title";
    SPAN.innerHTML = "I AM SLOTTED in the SLOT name='title'";
    
    DIV.append(SPAN); // put me in LIGHTDOM!
    
    console.log(SLOT1.assignedNodes()); // nothing assigned to default slot

    Be aware!

    Any whitespace and linebreaks in your HTML IS slotted to the default <slot></slot> !