Slot Change Events — Complete Guide
DodaTech
Updated 2026-06-28
2 min read
In this tutorial, you will learn about Slot Change Events. We cover key concepts, practical examples, and best practices to help you master this topic.
Slotchange events fire when slot content changes, enabling components to react dynamically to content additions, removals, or reconfiguration.
What You'll Learn
- How to listen for slotchange events
- When slotchange fires and when it does not
- How to access assigned nodes
- How to use slotchange for dynamic layouts
Why It Matters
Components often need to know when their slotted content changes. A tabs component needs to recount panels. A list component needs to update item count.
flowchart LR A[Slot Content Changes] --> B[slotchange Event] B --> C[assignedNodes] B --> D[assignedElements] C --> E[Process new nodes] D --> F[Update counts/layout]
Basic Slotchange
class SlotCounter extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
.counter { font-size: 0.9em; color: #666; margin-bottom: 8px; }
.list { border: 1px solid #ddd; border-radius: 4px; padding: 8px; }
</style>
<div class="counter">Items: <span id="count">0</span></div>
<div class="list"><slot id="slot"></slot></div>
`;
const slot = this.shadowRoot.getElementById('slot');
slot.addEventListener('slotchange', (e) => {
const nodes = slot.assignedNodes();
const elements = slot.assignedElements();
const count = elements.length;
console.log('Slot changed:', count, 'elements');
this.shadowRoot.getElementById('count').textContent = count;
});
}
}
customElements.define('slot-counter', SlotCounter);
Advanced Slot Tracking
class DynamicTabs extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
.tab-bar { display: flex; gap: 4px; margin-bottom: 8px; }
.tab { padding: 8px 16px; cursor: pointer; border: 1px solid #ddd; border-radius: 4px 4px 0 0; }
.tab.active { background: #3498db; color: white; border-color: #3498db; }
.panels { border: 1px solid #ddd; padding: 16px; border-radius: 0 4px 4px 4px; }
.panel { display: none; }
.panel.active { display: block; }
</style>
<div class="tab-bar" id="tabBar"></div>
<div class="panels"><slot id="panelSlot"></slot></div>
`;
const slot = this.shadowRoot.getElementById('panelSlot');
slot.addEventListener('slotchange', () => this._rebuildTabs());
}
_rebuildTabs() {
const panels = this.shadowRoot.getElementById('panelSlot').assignedElements();
const tabBar = this.shadowRoot.getElementById('tabBar');
tabBar.innerHTML = '';
panels.forEach((panel, index) => {
const tab = document.createElement('button');
tab.className = 'tab' + (index === 0 ? ' active' : '');
tab.textContent = panel.getAttribute('title') || 'Tab ' + (index + 1);
tab.addEventListener('click', () => this._selectTab(index));
tabBar.appendChild(tab);
panel.classList.toggle('active', index === 0);
});
}
_selectTab(index) {
const tabs = this.shadowRoot.querySelectorAll('.tab');
const panels = this.shadowRoot.getElementById('panelSlot').assignedElements();
tabs.forEach((t, i) => t.classList.toggle('active', i === index));
panels.forEach((p, i) => p.classList.toggle('active', i === index));
}
}
customElements.define('dynamic-tabs', DynamicTabs);
Common Mistakes
- Expecting slotchange to fire on initial assignment (it does not)
- Processing slotchange before the element is connected
- Not using assignedElements() when only HTMLElements are needed
Practice Questions
- When does slotchange fire? When the assigned nodes change, not on initial assignment.
- How do you get only element nodes from a slot? Use slot.assignedElements().
Mini Project
Build a todo list component that tracks its item count via slotchange. Show a message when the list is empty. Allow adding and removing items dynamically.
What's Next
Lesson 11: Event Retargeting
← Previous
CSS Parts in Shadow DOM — Complete Guide
Next →
Event Retargeting in Shadow DOM — Complete Guide
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro