Signatur
Beschreibung
Die Methode elementsFromPoint() des ShadowRoot-Interfaces liefert alle Elemente, die an einem bestimmten Punkt im Viewport liegen. Das Array ist nach der Stapelreihenfolge (Painting Order) sortiert: Das erste Element ist das oberste, das letzte ist in der Regel <html>. Die Methode stammt aus dem Mixin DocumentOrShadowRoot und verhält sich wie document.elementsFromPoint(), nur aus der Sicht des jeweiligen Shadow Trees.
Der Unterschied liegt beim Retargeting: document.elementsFromPoint() sieht bei einem Web Component nur den Host, nicht dessen Innenleben. Wird die Methode dagegen auf einem ShadowRoot aufgerufen, enthält das Ergebnis auch die Elemente innerhalb dieses Shadow Trees. Elemente aus verschachtelten Shadow Roots werden weiterhin auf deren Host umgeleitet.
Typische Einsatzfälle sind Drag-and-drop-Logik innerhalb von Web Components, eigene Tooltips oder Kontextmenüs, Hit-Testing für Overlays und das Debuggen von Elementen, die sich überlagern. Die Koordinaten beziehen sich immer auf den Viewport (wie clientX/clientY eines Events), nicht auf das Dokument oder den Host.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $x Pflicht | number | Horizontale Koordinate in CSS-Pixeln, relativ zur linken Kante des Viewports (z. B. event.clientX). |
|
| $y Pflicht | number | Vertikale Koordinate in CSS-Pixeln, relativ zur oberen Kante des Viewports (z. B. event.clientY). |
Rückgabewert
Array (keine NodeList) mit allen Elementen am Punkt, vom obersten zum untersten sortiert. Liegt der Punkt außerhalb des Viewports, ist das Array leer.Beispiele
Elemente innerhalb eines Web Components ermitteln
class InfoCard extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = `
<style>div { padding: 20px; background: #eef; }</style>
<div class="card"><span class="title">Hallo</span></div>
`;
}
}
customElements.define('info-card', InfoCard);
const card = document.createElement('info-card');
document.body.append(card);
const title = card.shadowRoot.querySelector('.title');
const { left, top } = title.getBoundingClientRect();
// Sicht des Shadow Roots: interne Elemente sichtbar
const inside = card.shadowRoot.elementsFromPoint(left + 1, top + 1);
console.log(inside.map((el) => el.localName));
// Sicht des Dokuments: nur der Host
const outside = document.elementsFromPoint(left + 1, top + 1);
console.log(outside.map((el) => el.localName));
Drop-Ziel beim Ziehen innerhalb der Komponente finden
const host = document.querySelector('task-board');
const root = host.shadowRoot;
root.addEventListener('pointermove', (event) => {
// Das gezogene Element selbst ignorieren
const hits = root.elementsFromPoint(event.clientX, event.clientY);
const dropZone = hits.find(
(el) => el.classList?.contains('drop-zone') && !el.classList.contains('dragging')
);
root.querySelectorAll('.drop-zone.active')
.forEach((el) => el.classList.remove('active'));
dropZone?.classList.add('active');
});
Überlagernde Elemente zum Debuggen ausgeben
const debugPoint = (shadowRoot, x, y) => {
const stack = shadowRoot.elementsFromPoint(x, y);
stack.forEach((el, i) => {
const { zIndex, pointerEvents } = getComputedStyle(el);
console.log(`${i}: <${el.localName}> z-index=${zIndex} pointer-events=${pointerEvents}`);
});
};
const widget = document.querySelector('my-widget');
debugPoint(widget.shadowRoot, 100, 50);
// Wichtig · Fallstricke
- Viewport-Koordinaten: Werte wie
pageX/pageYberücksichtigen den Scroll-Offset und liefern bei gescrollter Seite falsche Treffer. VerwendeclientX/clientYodergetBoundingClientRect(). - pointer-events: none: Elemente mit
pointer-events: nonetauchen nicht im Ergebnis auf. Das ist praktisch, um beim Drag-and-drop das gezogene Element auszublenden, kann aber auch unerwartet Elemente verbergen. - Verschachtelte Shadow Roots werden nicht durchsucht, ihre Inhalte erscheinen nur als Host-Element. Für tiefere Ebenen musst du die Methode auf dem jeweiligen inneren
shadowRootaufrufen. - Geschlossene Shadow Roots (
mode: 'closed'): Von außen gibt es keinen Zugriff überelement.shadowRoot. Die Methode funktioniert dann nur mit einer intern gespeicherten Referenz. - Das Ergebnis enthält Vorfahren außerhalb des Shadow Trees (Host,
body,html). Filtere bei Bedarf mitroot.contains(el). - Jeder Aufruf löst ein Layout aus. Häufige Aufrufe in
pointermovesolltest du mitrequestAnimationFramedrosseln. - Kompatibilität: Wird in allen modernen Browsern unterstützt. Ältere Chrome-Versionen kannten nur das nicht standardisierte
elementsFromPointaufdocument, und der Internet Explorer hattemsElementsFromPoint().