Start · Sprachen · JavaScript · Referenz · ShadowRoot.elementsFromPoint()

ShadowRoot.elementsFromPoint()

Methode

Gibt ein Array aller Elemente an den Viewport-Koordinaten <code>(x, y)</code> zurück – vom obersten zum untersten, aus Sicht eines Shadow Trees.

seit JavaScript Baseline: alle modernen Browser (Chrome 53+, Firef Kategorie: webapi

Signatur

ShadowRoot.prototype.elementsFromPoint(x, y)

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

Typ
Element[]
Beschreibung
Ein echtes 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));
["span", "div", "info-card", "body", "html"] ["info-card", "body", "html"]

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);
0: <button> z-index=auto pointer-events=auto 1: <div> z-index=10 pointer-events=auto 2: <my-widget> z-index=auto pointer-events=auto 3: <body> z-index=auto pointer-events=auto 4: <html> z-index=auto pointer-events=auto

// Wichtig · Fallstricke

  • Viewport-Koordinaten: Werte wie pageX/pageY berücksichtigen den Scroll-Offset und liefern bei gescrollter Seite falsche Treffer. Verwende clientX/clientY oder getBoundingClientRect().
  • pointer-events: none: Elemente mit pointer-events: none tauchen 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 shadowRoot aufrufen.
  • Geschlossene Shadow Roots (mode: 'closed'): Von außen gibt es keinen Zugriff über element.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 mit root.contains(el).
  • Jeder Aufruf löst ein Layout aus. Häufige Aufrufe in pointermove solltest du mit requestAnimationFrame drosseln.
  • Kompatibilität: Wird in allen modernen Browsern unterstützt. Ältere Chrome-Versionen kannten nur das nicht standardisierte elementsFromPoint auf document, und der Internet Explorer hatte msElementsFromPoint().