JavaScript Event composed Property

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
Baseline Widely available
Instance property

What You’ll Learn

The composed property is a read-only boolean on every Event: true if the event can cross the shadow DOM boundary into the light DOM, false if the shadow root is the last stop. Learn how it pairs with bubbles, how to set it on synthetic events, and how composedPath() reveals the path—with five examples and try-it labs.

01

Kind

Instance property

02

Type

boolean (read-only)

03

Means

Cross shadow boundary?

04

Set via

Constructor options

05

Path

composedPath()

06

Status

Baseline widely

Introduction

Web Components hide markup inside a shadow tree. Some events that start inside that tree should still reach listeners on the page outside—others should stay private. event.composed is the flag that answers that question.

Browser UI events such as click are composed, so a click inside a custom element can still be heard on document. Most custom synthetic events are not composed unless you pass { composed: true } to new Event().

💡
Beginner tip

MDN: crossing the shadow boundary for bubbling still needs bubbles: true as well. Think of composed as “allowed to leave the shadow tree” and bubbles as “travels up ancestors.”

Understanding Event.composed

An instance property that answers: “After this event reaches the shadow root, may it continue into the standard DOM?”

  • Valuetrue if it can cross; false if the shadow root is the last node.
  • Read-only — set only at construction for synthetic events.
  • UI events — browser click / touch / mouseover / copy / paste (and similar) are composed.
  • With bubbles — bubble-phase travel across the boundary needs bubbles too.
  • Baseline Widely available on MDN (since January 2020); also in Web Workers.

📝 Syntax

JavaScript
event.composed

Value

A boolean: true if the event will cross from the shadow DOM into the standard DOM after reaching the shadow root.

Set on synthetic events

JavaScript
const privateEvt = new Event("notify"); // composed: false (default)
const publicEvt = new Event("notify", { bubbles: true, composed: true });

console.log(privateEvt.composed); // false
console.log(publicEvt.composed);  // true

See the path

JavaScript
document.addEventListener("click", (e) => {
  console.log(e.composed);
  console.log(e.composedPath());
});

🎨 Open vs Closed Shadow Roots

MDN’s classic demo defines custom elements with mode: "open" and mode: "closed". Clicks are always composed === true, but composedPath() differs:

  • Open — path can include inner nodes (for example a p inside the shadow root).
  • Closed — outer listeners often see the host element, not the private inner nodes.

That protects encapsulation while still letting composed UI events reach the page.

⚡ Quick Reference

GoalCode / note
Readevent.composed
Create composed eventnew Event("x", { bubbles: true, composed: true })
Default for new Eventcomposed: false
Inspect pathevent.composedPath()
MDN statusBaseline Widely available (since January 2020)

🔍 At a Glance

Four facts to remember about Event.composed.

Type
boolean

Read-only

true means
can leave

Shadow → light DOM

Needs
bubbles

For bubble travel

Baseline
widely

Since Jan 2020

Examples Gallery

Examples follow MDN Event: composed. Use View Output or Try It Yourself.

📚 Getting Started

Read the flag and set it on synthetic events.

Example 1 — Read composed on a Click

Browser clicks are composed—log the property on click.

JavaScript
document.getElementById("btn").addEventListener("click", (event) => {
  console.log("composed =", event.composed); // true for click
});
Try It Yourself

How It Works

UA-dispatched UI events are composed, so they can leave shadow trees.

Example 2 — composed: true vs Default

Compare two synthetic events with different options.

JavaScript
const a = new Event("notify"); // default composed: false
const b = new Event("notify", { composed: true });

console.log(a.composed); // false
console.log(b.composed); // true
Try It Yourself

How It Works

Custom events stay inside the shadow tree unless you opt in with composed: true.

📈 Paths & Shadow Trees

composedPath, dispatch from shadow, and open vs closed roots.

Example 3 — Log composedPath()

See which nodes are on the event path for a click.

JavaScript
document.querySelector("html").addEventListener("click", (e) => {
  console.log("composed =", e.composed);
  console.log(
    e.composedPath().map((n) => n.nodeName || n.toString()).join(" → ")
  );
});
Try It Yourself

How It Works

composedPath() is the practical companion to the composed boolean when debugging Web Components.

Example 4 — Dispatch Inside Shadow: Composed vs Not

Only a composed + bubbling event reaches a listener on the host’s parent.

JavaScript
const host = document.getElementById("host");
const root = host.attachShadow({ mode: "open" });
const inner = document.createElement("button");
inner.textContent = "Inside shadow";
root.appendChild(inner);

document.body.addEventListener("notify", () => {
  console.log("body heard notify");
});

// Stays in shadow (not composed):
inner.dispatchEvent(new Event("notify", { bubbles: true }));

// Leaves shadow:
inner.dispatchEvent(
  new Event("notify", { bubbles: true, composed: true })
);
Try It Yourself

How It Works

Both dispatches bubble inside the shadow tree; only composed: true continues past the shadow root.

Example 5 — Open vs Closed Shadow (MDN Idea)

Clicks are composed; composedPath() shows different detail for open vs closed.

JavaScript
// After defining  and  like MDN:
document.querySelector("html").addEventListener("click", (e) => {
  console.log(e.composed); // true for click
  console.log(e.composedPath());
  // Open: may include inner 

, ShadowRoot, host, ... // Closed: often starts at the host, without inner nodes });

Try It Yourself

How It Works

Encapsulation changes what outer code can see on the path, not whether a click is composed.

🚀 Common Use Cases

  • Custom element events that the page (or a parent) must hear.
  • Keeping internal component signals private (composed: false).
  • Debugging event paths with composedPath().
  • Understanding why a click escapes shadow DOM but a custom event does not.
  • Designing APIs for design systems built on Web Components.

🔧 How It Works

1

Event starts

Inside light DOM or inside a shadow tree.

Origin
2

Reach shadow root

If the event is in a shadow tree, it arrives at the root.

Boundary
3

Check composed

true may continue to the light DOM; false stops at the root.

Flag
4

Outer listeners

Hear the event when composed (and bubbles, for bubble phase).

📝 Notes

  • MDN: Baseline Widely available (since January 2020) — no Deprecated / Experimental / Non-standard banner.
  • Available in Web Workers.
  • Read-only—set via constructor options for synthetic events.
  • Bubble across shadow needs bubbles as well as composed.
  • Related learning: bubbles, cancelable, Event(), addEventListener(), JavaScript hub.

Universal Browser Support

Event.composed is marked Baseline Widely available on MDN (since January 2020). Logos use the shared browser-image-sprite.png sprite from this project. It is also available in Web Workers.

Baseline · Widely available

Event.composed

Read-only boolean: true if the event can cross the shadow DOM boundary into the standard DOM.

Universal Widely available
Google Chrome Full support · Desktop & Mobile
Full support
Mozilla Firefox Full support · Desktop & Mobile
Full support
Apple Safari Full support · macOS & iOS
Full support
Microsoft Edge Full support · Chromium
Full support
Opera Full support · Modern versions
Full support
Internet Explorer Not supported
Unavailable
Event.composed Excellent

Bottom line: Use composed for shadow-aware event design. Pair with bubbles for bubble-phase escape, and inspect paths with composedPath().

Conclusion

Event.composed tells you whether an event may leave a shadow tree for the light DOM. Browser UI events usually can; your synthetic events only can if you set { composed: true }.

Continue with currentTarget, bubbles, Event(), or the JavaScript hub.

💡 Best Practices

✅ Do

  • Pass { bubbles: true, composed: true } for public component events
  • Keep internal signals non-composed by default
  • Use composedPath() when debugging shadow events
  • Remember UI events like click are already composed
  • Document which custom events are meant to escape the shadow tree

❌ Don’t

  • Assign event.composed = true after creation
  • Expect non-composed events to reach document from shadow
  • Forget bubbles when you need bubble-phase escape
  • Assume closed shadow paths include private inner nodes
  • Confuse composed with cancelable

Key Takeaways

Knowledge Unlocked

Five things to remember about composed

Shadow-boundary flag for Web Component events.

5
Core concepts
🔁02

true

can leave shadow

Meaning
📝03

Set once

constructor options

Create
📈04

composedPath

see the route

Debug
🎯05

Baseline

since Jan 2020

Status

❓ Frequently Asked Questions

It is a read-only boolean on an Event. It is true if the event can cross the shadow DOM boundary into the standard DOM after reaching the shadow root, and false if the shadow root is the last node offered the event.
No. MDN marks Event.composed as Baseline Widely available (since January 2020). It is not Deprecated, Experimental, or Non-standard. It is also available in Web Workers.
No. Browser-dispatched UI events (click, touch, mouseover, copy, paste, and similar) are composed. Most other event types are not, including synthetic events created without { composed: true }.
Propagation across the boundary still needs bubbling when you rely on the bubble phase. MDN notes propagation only occurs if bubbles is also true. composedPath() shows the path the event follows.
Use new Event("my-event", { bubbles: true, composed: true }) (and cancelable if needed), then dispatch it from inside the shadow tree when outer listeners must hear it.
event.composedPath() returns an array of objects the event will travel through, including nodes across shadow boundaries when the event is composed. Closed shadow roots may hide inner nodes from the path seen outside.
Did you know?

MDN notes that capturing-only composed events are still handled at the host as if they were in the AT_TARGET phase—another reason shadow hosts feel like special targets for composed UI events.

Next: currentTarget

Learn currentTarget vs target for event handlers.

currentTarget →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful