Shadow DOM Slots - Composition
Web Components: Shadow DOM Slots - Composition
What is the HTML named <slot> element used for in web development?
View Answer:
Why are Slots used in Web Components?
View Answer:
How many types of slots are there?
View Answer:
<template id="myComponent">
<div>
<slot name="header"></slot> <!-- named slot -->
<slot></slot> <!-- default slot -->
</div>
</template>
<script>
class MyComponent extends HTMLElement {
connectedCallback() {
const template = document.getElementById('myComponent');
const node = document.importNode(template.content, true);
this.attachShadow({mode: 'open'}).appendChild(node);
}
}
customElements.define('my-component', MyComponent);
</script>
<my-component>
<h1 slot="header">Hello World</h1> <!-- content for named slot -->
<p>This is some text.</p> <!-- content for default slot -->
</my-component>
In this example, we create a Web Component with a named slot (for a header) and a default slot. We then use the custom element, providing content for both slots.
What's the difference between a named slot and a default slot?
View Answer:
How can you select elements assigned to slots in Shadow DOM?
View Answer:
<template id="myComponent">
<div>
<slot name="header"></slot> <!-- named slot -->
<slot></slot> <!-- default slot -->
</div>
</template>
<script>
class MyComponent extends HTMLElement {
connectedCallback() {
const template = document.getElementById('myComponent');
const node = document.importNode(template.content, true);
this.attachShadow({mode: 'open'}).appendChild(node);
// After the node is attached
this.shadowRoot.addEventListener('slotchange', function(e) {
let slotElement = e.target;
let nodes = slotElement.assignedElements();
nodes.forEach(node => console.log(node.tagName)); // Outputs the tag names of the assigned elements
});
}
}
customElements.define('my-component', MyComponent);
</script>
<my-component>
<h1 slot="header">Hello World</h1> <!-- content for named slot -->
<p>This is some text.</p> <!-- content for default slot -->
</my-component>
In this example, after the Shadow DOM is attached, a 'slotchange' event listener is added. Whenever a slot change occurs, it selects the slot that changed (e.target), gets all elements assigned to that slot with slotElement.assignedElements(), and logs the tag name of each assigned element.
What's the difference between assignedNodes and assignedElements?
View Answer:
<template id="myComponent">
<div>
<slot name="header"></slot> <!-- named slot -->
</div>
</template>
<script>
class MyComponent extends HTMLElement {
connectedCallback() {
const template = document.getElementById('myComponent');
const node = document.importNode(template.content, true);
this.attachShadow({mode: 'open'}).appendChild(node);
// After the node is attached
this.shadowRoot.addEventListener('slotchange', function(e) {
let slotElement = e.target;
let nodes = slotElement.assignedNodes();
let elements = slotElement.assignedElements();
console.log('assignedNodes: ', nodes);
console.log('assignedElements: ', elements);
});
}
}
customElements.define('my-component', MyComponent);
</script>
<my-component>
<span slot="header">Hello </span>World <!-- content for named slot -->
</my-component>
In this example, slotElement.assignedNodes() returns both the <span> element and the following text node ("World"), while slotElement.assignedElements() only returns the <span> element.
Can you change the slot an element is assigned to?
View Answer:
<template id="myComponent">
<div>
<slot name="header"></slot> <!-- named slot -->
<slot name="footer"></slot> <!-- another named slot -->
</div>
</template>
<script>
class MyComponent extends HTMLElement {
connectedCallback() {
const template = document.getElementById('myComponent');
const node = document.importNode(template.content, true);
this.attachShadow({mode: 'open'}).appendChild(node);
}
}
customElements.define('my-component', MyComponent);
</script>
<my-component>
<h1 slot="header">Hello World</h1> <!-- content for named slot -->
</my-component>
<button onclick="changeSlot()">Change Slot</button>
<script>
function changeSlot() {
const h1 = document.querySelector('my-component h1');
h1.setAttribute('slot', 'footer'); // Changes the slot from "header" to "footer"
}
</script>
In this example, there's a <h1> element initially assigned to the "header" slot. When the "Change Slot" button is clicked, the changeSlot() function changes the slot attribute of the <h1> element from "header" to "footer", thereby changing which slot it is assigned to. After the function runs, the <h1> element is assigned to the "footer" slot instead of the "header" slot.
What happens when multiple elements have the same slot name?
View Answer:
HTML (Light DOM):
<my-element>
<p slot="same-slot">First</p>
<p slot="same-slot">Second</p>
<p slot="same-slot">Third</p>
</my-element>
HTML (Shadow DOM):
<template id="my-element-template">
<div>
<slot name="same-slot"></slot>
</div>
</template>
<script>
class MyElement extends HTMLElement {
constructor() {
super();
let shadowRoot = this.attachShadow({mode: 'open'});
let template = document.getElementById('my-element-template');
shadowRoot.appendChild(template.content.cloneNode(true));
}
}
customElements.define('my-element', MyElement);
</script>
In this case, the shadow DOM has a single slot named same-slot. The light DOM of the custom element my-element has three <p> elements, each also assigned to same-slot. When the browser renders this, the content assigned to same-slot in the light DOM gets inserted into the same-slot slot of the shadow DOM. Since there are multiple elements assigned to same-slot, they are inserted in order. So the resulting rendered HTML would look like:
<my-element>
<div>
<p slot="same-slot">First</p>
<p slot="same-slot">Second</p>
<p slot="same-slot">Third</p>
</div>
</my-element>
So the answer to your question is, when multiple elements have the same slot name, they are inserted into the slot in the order they appear in the light DOM.
Can a web component have more than one slot?
View Answer:
What happens to elements that don't have a slot attribute?
View Answer:
What happens if there is no default slot?
View Answer:
Is it necessary to use slots when creating custom elements?
View Answer:
What happens when a slot is deleted from the Shadow DOM?
View Answer:
Can a slotted element access data from the shadow host?
View Answer:
What is the definition of a flattened DOM?
View Answer:
What is the slot attribute's principal limitation?
View Answer:
<!-- invalid slot, must be direct child of user-card -->
<span slot="birthday">01.01.2001</span>
</div>
</user-card>
<!-- The slots below are appended in order -->
<user-card>
<span slot="username">John</span>
<span slot="username">Smith</span>
</user-card>
Can you explain what slot fallback content is in browser rendering?
View Answer:
In the Shadow DOM, what is the default slot?
View Answer:
<script>
customElements.define(
'user-card',
class extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
`;
}
}
);
</script>
<user-card>
<div>I like to swim.</div>
<span slot="username">John Smith</span>
<span slot="birthday">01.01.2001</span>
<div>...And play volleyball too!</div>
</user-card>
What are the three methods that handle HTML slot element assignment?
View Answer:
<custom-menu id="menu">
<span slot="title">Candy menu</span>
<li slot="item">Lollipop</li>
<li slot="item">Fruit Toast</li>
</custom-menu>
<script>
customElements.define(
'custom-menu',
class extends HTMLElement {
items = [];
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
`;
// triggers when slot content changes
this.shadowRoot.firstElementChild.addEventListener(
'slotchange',
(e) => {
let slot = e.target;
if (slot.name == 'item') {
this.items = slot
.assignedElements()
.map((elem) => elem.textContent);
console.log('Items: ' + this.items);
}
}
);
}
}
);
// items update after 1 second
setTimeout(() => {
menu.insertAdjacentHTML('beforeEnd', '<li slot="item">Cup Cake</li>');
}, 1000);
</script>