<label for="my-checkbox">Checkbox value (click me to toggle checkbox)</label>
<custom-checkbox id="my-checkbox">
<template shadowrootmode="open" shadowrootreferencetarget="real-checkbox">
<input id="real-checkbox" type="checkbox">
</template>
</custom-checkbox>
Description
Source
Demo
Label
Label association across shadow DOM.
A <label> element in the light DOM targets an
<input> inside a custom element's shadow tree via
referenceTarget, enabling click-to-focus and
accessibility wiring without exposing internals (try clicking "Checkbox value").
Popover
Popover invocation across shadow DOM.
A button[popovertarget] in the light DOM toggles a
popover living inside a custom element's shadow tree, using
referenceTarget to bridge the encapsulation boundary.
<button popovertarget="custom-popover">Toggle popover</button>
<custom-popover id="custom-popover">
<template shadowrootmode="open" shadowrootreferencetarget="real-popover">
<style>
[popover] { border-radius: 50%; padding: 5em 1em; }
</style>
<div id="real-popover" popover>Here's the popover content</div>
</template>
</custom-popover>
aria-labelledby
Fine-grained ARIA labelling.
In some cases we might want to use only part of a component's shadow
content as the accessible name for another element. aria-labelledby
can be combined with referenceTarget to achieve this by pointing to a
specific element inside the shadow tree.
<input aria-labelledby="fancy-label">
<fancy-description id="fancy-label">
<template shadowrootmode="open" shadowrootreferencetarget="inner-label">
<div id="inner-label">This is the text we want to use as the accessible name.</div>
<div>This other text won't be included in the accessible name.</div>
</template>
</fancy-description>
Things Reference Target does ⚠️ not ⚠️ do
To clear up misconceptions about what reference target does, the following table shows some scenarios that are out of scope.
Description
Source
Attribute forwarding
Attribute forwarding is not supported.
The referenceTarget attribute does not copy attributes from the light DOM to elements inside the shadow tree.
<fancy-description aria-label="This is an accessible name">
<template shadowrootmode="open" shadowrootreferencetarget="inner-element">
<div id="inner-element">The aria-label attribute does not get forwarded to this element.</div>
</template>
</fancy-description>
References out of shadow DOM
References out of the shadow DOM are not supported.
The referenceTarget attribute only works for ID references pointing *into* a shadow tree, but not for references pointing out of the shadow DOM.
<custom-button popovertarget="my-popover">
<template shadowrootmode="open" shadowrootreferencetarget="real-button">
<!-- The popovertarget reference isn't forwarded, so this doesn't work. Put another way,
reference target only works for ID references pointing *into* a shadow, but in this case
the ID reference needs to be pointing out of the shadow, from the button to the popover. -->
<button id="real-button">Open popover?</button>
</template>
</custom-button>
<div id="my-popover" popover>Popover contents</div>
<!-- There's an alternative way to do this however, setting up the reference using JS: -->
<working-custom-button popovertarget="my-working-popover">
<template shadowrootmode="open">
<button id="real-button">Open popover?</button>
</template>
</working-custom-button>
<div id="my-working-popover" popover>Popover contents</div>
<script>
customElements.define("working-custom-button", class WorkingCustomButton extends HTMLElement {
constructor() {
super();
this._internals = this.attachInternals();
const real_button = this._internals.shadowRoot.querySelector("#real-button");
const popover = document.querySelector("#my-working-popover");
// Use script to set up the reference to the popover, pointing *out*
// of the shadow. Note that references set up this way can only
// point *out* of a shadow root or to a node in the same root.
// For references pointing *into* a shadow, we need reference target.
real_button.popoverTargetElement = popover;
}
});
</script>