Skip to main content

SF-9008 · Scenario · Medium

How does a child LWC communicate back to its parent?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

Children push information upward by dispatching a CustomEvent. The parent listens for the event in its template using the on<eventname> syntax. This is the same DOM event model every browser already implements — LWC just uses it directly.

The minimal pattern

// rowItem.js
import { LightningElement, api } from 'lwc';

export default class RowItem extends LightningElement {
    @api contact;

    handleSelect() {
        const event = new CustomEvent('contactselect', {
            detail: { contactId: this.contact.Id, name: this.contact.Name }
        });
        this.dispatchEvent(event);
    }
}
<!-- rowItem.html -->
<template>
    <li onclick={handleSelect}>{contact.Name}</li>
</template>
<!-- parentList.html -->
<template>
    <ul>
        <template for:each={contacts} for:item="c">
            <c-row-item key={c.Id} contact={c} oncontactselect={handleSelect}></c-row-item>
        </template>
    </ul>
</template>
// parentList.js
handleSelect(event) {
    console.log('Selected:', event.detail.contactId);
}

The four rules of LWC event naming

LWC is stricter than vanilla DOM events. Event names must:

  1. Be all lowercase. contactselect, not contactSelect or contact-select.
  2. Contain no underscores or hyphens. Just letters.
  3. Be short and dot-free. No namespacing.
  4. Not start with on. That’s reserved for the listener syntax.

The reasons trace back to HTML attribute case-insensitivity — oncontactselect and oncontactSelect would be the same attribute, so LWC enforces lowercase to keep things predictable.

Crossing shadow boundaries: bubbles and composed

By default a CustomEvent only travels within the component that dispatched it. If you need it to cross the shadow DOM boundary, set the right flags:

this.dispatchEvent(new CustomEvent('rowselect', {
    detail: { id: this.id },
    bubbles: true,   // travel up the tree, not just the dispatcher
    composed: true   // cross shadow root boundaries
}));
Scenariobubblescomposed
Parent listens to its own direct childfalsefalse
Grandparent listens to a descendant (same shadow)truefalse
Anywhere outside the shadow root needs to hear ittruetrue

Avoid composed: true unless you really need it. Composed events break encapsulation — any ancestor anywhere can intercept them, including code you don’t control. The Salesforce guidance is to keep events scoped, propagating data via @api props on the way down and dispatching only to direct parents on the way up.

Passing data with detail

The detail property carries your payload. Two practices worth calling out:

Always send objects, not loose primitives. A future-proof event has room to grow:

// fragile — adding a second field is a breaking change
new CustomEvent('save', { detail: contactId });

// flexible
new CustomEvent('save', { detail: { contactId, source: 'inline-edit' } });

Freeze detail or send a copy. If you pass an internal object as detail, the parent receives the same reference and can mutate your state:

new CustomEvent('change', { detail: { ...this.draft } });   // copy

Event handler syntax

You can bind handlers in markup or imperatively in JavaScript:

<!-- declarative — preferred -->
<c-row-item oncontactselect={handleSelect}></c-row-item>
// imperative — when you need add/removeEventListener
connectedCallback() {
    this.template.host.addEventListener('contactselect', this.handler);
}
disconnectedCallback() {
    this.template.host.removeEventListener('contactselect', this.handler);
}

The declarative form covers 95% of cases. Reach for addEventListener only when you need event capture, or when you’re working with non-LWC host elements.

Common interview follow-ups

  • “Why are LWC event names lowercase?” — HTML attributes are case-insensitive, so on-handler attributes can only match a single canonical form.
  • “What happens if the parent doesn’t listen?” — the event bubbles up the DOM (if bubbles: true) or simply gets dropped. No error, no warning.
  • “How is this different from Aura’s aura:registerEvent?” — Aura uses a typed event registry. LWC uses the browser-native CustomEvent API. Less ceremony, but you lose the static-typing safety net Aura provided.

Verified against: LWC Developer Guide — Create and Dispatch Events. Last reviewed 2026-05-17 for Spring ‘26 release.