← Reference Target for Cross-root ARIA

v152 · web components · idl member

ShadowRoot.referenceTarget

The JavaScript surface for Reference Target: a settable DOMString? on ShadowRoot holding the ID of the element in the shadow tree that IDREFs to the host should resolve to — settable at creation time via the ShadowRootInit.referenceTarget dictionary member, or declaratively via the shadowrootreferencetarget template attribute and its HTMLTemplateElement.shadowRootReferenceTarget reflection.

Experimental outside Chrome 152+ Every engine record in BCD is currently flag-gated (Chrome 133+ #enable-experimental-web-platform-features; Firefox 144+ dom.shadowdom.referenceTarget.enabled; Safari 26+ referenceTarget) and BCD has not yet recorded Chrome 152's enabled-by-default milestone. Feature-detect: "referenceTarget" in ShadowRoot.prototype.

syntax

Verbatim from Chromium's shadow_root.idl (the comment is part of the source):

// The referenceTarget attribute is the ID of an element in the shadow tree.
// When the host element is the target of an IDREF attribute like
// aria-activedescendant, the reference resolves to the referenceTarget.
// See https://crbug.com/346835896
[RuntimeEnabled=ShadowRootReferenceTarget] attribute DOMString? referenceTarget;

The ShadowRootInit dictionary member, verbatim from shadow_root_init.idl:

dictionary ShadowRootInit {
  required ShadowRootMode mode;
  boolean delegatesFocus;
  SlotAssignmentMode slotAssignment;
  [RuntimeEnabled=ScopedCustomElementRegistry] CustomElementRegistry? customElementRegistry;
  boolean serializable;
  boolean clonable;
  [RuntimeEnabled=ShadowRootReferenceTarget] DOMString? referenceTarget;
  // Note: if you add a parameter here, be sure to add it to the list of checks
  // in Element::attachShadow() for existing declarative shadow roots.
};

And the declarative-shadow-DOM reflection, verbatim from html_template_element.idl:

[CEReactions, Reflect, RuntimeEnabled=ShadowRootReferenceTarget]
attribute DOMString? shadowRootReferenceTarget;
Source: shadow_root.idl; shadow_root_init.idl; html_template_element.idl — all fetched 2026-07-28

inputs (setting)

shadowRoot.referenceTarget = valueAny DOMString or null. The value is the id of an element in the shadow tree; it is stored as given (no validation at set time — resolution happens live, at reference-lookup time)
attachShadow({ referenceTarget })Same value space via the ShadowRootInit dictionary; sets the initial reference target at creation, for both open and closed roots (the explainer's sp-checkbox uses a closed root)
<template shadowrootreferencetarget>Content attribute taking the target ID; parsed when the declarative shadow root attaches. Reflected by HTMLTemplateElement.shadowRootReferenceTarget (DOMString?, [CEReactions, Reflect]) — reading the reflection on a still-present template returns the attribute value
Missing/unknown IDNot an error. Resolution is by ID lookup in the shadow tree at reference-lookup time; if nothing matches, forwarding simply has no target until a matching element exists (see lifecycle — references are live)
Source: shadow_root.idl (type DOMString?, no RaisesException); WICG explainer — Phase 1, Live references

outputs (getting)

The getter returns the current value as a DOMString? — the ID string last set (via IDL, ShadowRootInit, or the declarative attribute), or null when no reference target is set. It returns the ID string, not the element: resolving the string to an element is the engine's job at IDREF-lookup time; script that wants the element does its own shadowRoot.getElementById(value). On a closed root the property exists on the ShadowRoot object but is only reachable where script retained a reference to that root — it does not leak through the host.

Source: shadow_root.idl (attribute DOMString?); WICG explainer — sp-checkbox (closed root)

errors and edge cases

Setter exceptionsNone — the IDL carries no RaisesException on this attribute; any string (or null) is accepted
attachShadow exceptionsattachShadow() itself can throw for unrelated reasons (e.g. a second attach on the same host, or a declarative-shadow-root mismatch — the dictionary comment notes new members are added to the existing-DSD checks in Element::attachShadow()); none of these are specific to referenceTarget
Duplicate IDsThe explainer defines resolution as an ID lookup in the shadow tree; normal getElementById-style first-match rules apply. Not separately specified in the sources read — treat duplicate IDs in the shadow tree as an authoring error
aria-owns forwardingRequires the separate ShadowRootReferenceTargetAriaOwns flag, which has no status field in runtime_enabled_features.json5 (not enabled anywhere by default; WICG/webcomponents #1091) — do not rely on aria-owns forwarding in Chrome 152
Source: shadow_root.idl; runtime_enabled_features.json5; WICG/webcomponents #1091

context and exposure

ShadowRoot.referenceTarget and the ShadowRootInit member are exposed in Window (the interface is [Exposed=Window]) and gated by the ShadowRootReferenceTarget runtime feature (status: "stable" at trunk; origin_trial_feature_name: "ShadowRootReferenceTarget" for the concluded 133–135 origin trial). The template reflection is likewise [RuntimeEnabled=ShadowRootReferenceTarget]. Feature-detect:

const supported = "referenceTarget" in ShadowRoot.prototype;
Source: runtime_enabled_features.json5; shadow_root.idl

lifecycle and live updates

The reference target is a live reference: the engine re-resolves it whenever the relevant state changes. From the explainer (verbatim list):

Declarative roots serialize the setting: getHTML({ serializableShadowRoots: true }) emits shadowrootreferencetarget (WPT gethtml-serialization.html), and the dictionary comment in shadow_root_init.idl records that new ShadowRootInit members join the existing-declarative-root equality checks in Element::attachShadow() — an imperative re-attach over a declarative root must match the declarative referenceTarget value.

Source: WICG explainer — Live references; WPT gethtml-serialization.html; shadow_root_init.idl

examples

// Set at creation (open or closed root):
const root = host.attachShadow({ mode: "open", referenceTarget: "real-input" });
root.innerHTML = `<input id="real-input">`;

// Or later, via the IDL attribute:
root.referenceTarget = "other-input";

// Read back — an ID string or null:
console.log(root.referenceTarget);           // "other-input"
console.log(root.getElementById(root.referenceTarget)); // the element

// Declarative equivalent + reflection:
// <template shadowrootmode="open" shadowrootreferencetarget="real-checkbox">…</template>
console.log(templateEl.shadowRootReferenceTarget); // "real-checkbox"

Live-update behavior (from the explainer's guarantee): after root.referenceTarget = "other-input", an existing <label for="host-id"> immediately labels #other-input — no observer or re-registration needed.

Source: WICG explainer — Phase 1 examples; ChromeStatus summary (declarative example)

compatibility

EngineShadowRoot.referenceTargetshadowrootreferencetarget attribute
Chrome / Edge133 (flag) → 152 enabled by default (listing)Same (both BCD keys move together)
Firefox144 behind dom.shadowdom.referenceTarget.enabledSame
Safari26 behind referenceTarget (+ referenceTarget support for aria-owns)Same

BCD marks both entries experimental: true and does not yet record Chrome 152's default-on (checked 2026-07-28 — freshness gap; the milestone listing is authoritative for Chrome).

Source: BCD api/ShadowRoot.json; BCD html/elements/template.json; chromestatus milestone=152 listing

security and privacy

Reference Target is designed to preserve shadow encapsulation rather than weaken it: the only new information an outside page gains is that IDREFs to the host resolve to some internal element — the internal structure (which ID, what markup) is not exposed. Element-reflecting JavaScript getters deliberately return the host, never the internal target (interaction contract), so script cannot launder shadow-internal element references out through ariaControlsElements or HTMLLabelElement.control. CSS selectors and event retargeting are unaffected (WPT event-path.html). No new storage, network, or fingerprinting surface is introduced in the sources read.

Source: WICG explainer — JavaScript attributes that reflect Element objects, Interaction with CSS Selectors; WPT event-path.html

see also