Skip to content

Events in Web Components — Complete Guide

DodaTech Updated 2026-06-28 2 min read

In this tutorial, you will learn about Events in Web Components. We cover key concepts, practical examples, and best practices to help you master this topic.

Events in Web Components use CustomEvent for communication, with retargeting across shadow boundaries and composed events for cross-boundary propagation.

What You'll Learn

  • How to dispatch custom events from Web Components
  • How events are retargeted across shadow boundaries
  • The composed option for cross-boundary events
  • How to listen for events on custom elements

Why It Matters

Event communication is how components notify the outside world about user interactions, state changes, and completed actions.

flowchart LR
  A[Component] --> B[dispatchEvent]
  B --> C[CustomEvent]
  C --> D[detail: data]
  C --> E[bubbles: true]
  C --> F[composed: true]
  D --> G[Parent receives event]

Dispatching Events

class ToggleSwitch extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        this._on = this.hasAttribute('on');
        this.shadowRoot.innerHTML = `
            <style>
                .track { width: 44px; height: 24px; background: #ccc; border-radius: 12px; cursor: pointer; position: relative; transition: background 0.3s; }
                .thumb { width: 20px; height: 20px; background: white; border-radius: 50%; position: absolute; top: 2px; left: 2px; transition: left 0.3s; }
                :host([on]) .track { background: #2ecc71; }
                :host([on]) .thumb { left: 22px; }
            </style>
            <div class="track" part="track"><div class="thumb" part="thumb"></div></div>
        `;
        this.shadowRoot.querySelector('.track')
            .addEventListener('click', () => this.toggle());
    }

    toggle() {
        this._on = !this._on;
        if (this._on) {
            this.setAttribute('on', '');
        } else {
            this.removeAttribute('on');
        }
        this.dispatchEvent(new CustomEvent('toggle', {
            detail: { on: this._on },
            bubbles: true,
            composed: true
        }));
    }

    get on() { return this._on; }
}
customElements.define('toggle-switch', ToggleSwitch);

Event Retargeting

Shadow Dom retargets events so the host element appears as the target, not internal nodes.

// JavaScript
document.querySelector('toggle-switch').addEventListener('toggle', (e) => {
    console.log('Toggle event:', e.detail);
    console.log('Target:', e.target); // The <toggle-switch> element, not internal div
    console.log('Current target:', e.currentTarget);
});

Common Mistakes

  1. Forgetting to set composed: true on events that need to cross shadow boundaries
  2. Not setting bubbles: true for ancestor listening
  3. Dispatching events on internal elements instead of the host (this)

Practice Questions

  1. What does the composed option do? Allows the event to propagate across shadow DOM boundaries into the main DOM.
  2. How does event retargeting affect event.target? The target is changed to the host element instead of the internal shadow element.

Mini Project

Build a form component with multiple input child components. Each input dispatches a field-change event. The parent form listens and validates. Submit dispatches a form-submit event with all field values.

What's Next

Lesson 14: Form Participation

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro