Start · Sprachen · JavaScript · Referenz · Selection.getComposedRanges()

Selection.getComposedRanges()

Methode

Gibt die aktuelle Auswahl als Array von <code>StaticRange</code>-Objekten zurück. Die Bereiche können über Shadow-DOM-Grenzen hinweg reichen.

seit JavaScript Chrome/Edge 137+, Firefox 142+, Safari 17+ (Safari Kategorie: webapi

Signatur

Selection.prototype.getComposedRanges(options)

Beschreibung

getComposedRanges() ist die Shadow-DOM-taugliche Alternative zu Selection.getRangeAt(). Wenn der Nutzer Text markiert, der teilweise oder ganz innerhalb eines Shadow Trees liegt, liefert getRangeAt() meist nur einen Bereich, der auf den Baum des Dokuments beschränkt ist. getComposedRanges() dagegen kann Start- und Endpunkte zurückgeben, die direkt in Knoten eines Shadow Trees liegen. Voraussetzung ist, dass Sie die betreffenden ShadowRoot-Objekte ausdrücklich übergeben.

Die übergebenen Shadow Roots wirken wie eine Freigabeliste. Liegt ein Endpunkt der Auswahl in einem Shadow Tree, der nicht in shadowRoots steht, verschiebt der Browser diesen Endpunkt nach oben auf den zugehörigen Shadow Host. So werden gekapselte, besonders geschlossene (mode: "closed") Shadow Trees nicht versehentlich offengelegt. Die Kapselung bleibt also erhalten: Nur wer die Shadow Root bereits kennt, bekommt Zugriff auf ihre inneren Knoten.

Der Rückgabewert besteht aus StaticRange-Objekten und nicht aus lebendigen Range-Objekten. Sie werden also nicht aktualisiert, wenn sich das DOM ändert, und haben keine Methoden wie cloneContents() oder getBoundingClientRect(). Sie bieten nur startContainer, startOffset, endContainer, endOffset und collapsed. Brauchen Sie mehr, erzeugen Sie aus diesen Werten mit document.createRange() einen echten Range.

Typische Einsatzfälle sind Rich-Text-Editoren, Werkzeuge zum Markieren und Kommentieren sowie Kontextmenüs innerhalb von Web Components, bei denen die markierte Stelle genau bekannt sein muss.

Parameter

Name Typ Default Beschreibung
$options object {} Optionales Einstellungsobjekt.
$options.shadowRoots ShadowRoot[] [] Liste der ShadowRoot-Objekte, in deren Bäumen Endpunkte liegen dürfen. Endpunkte in nicht aufgeführten Shadow Trees werden auf den Shadow Host verschoben.

Rückgabewert

Typ
StaticRange[]
Beschreibung
Ein Array von StaticRange-Objekten. Gibt es keine Auswahl (rangeCount === 0), ist das Array leer. In heutigen Browsern enthält es höchstens einen Eintrag.

Beispiele

Einfache Auswahl im Dokument auslesen

const selection = document.getSelection();
const ranges = selection.getComposedRanges();

if (ranges.length === 0) {
  console.log('Nichts markiert');
} else {
  const [range] = ranges;
  console.log(range.startContainer.nodeName, range.startOffset);
  console.log(range.endContainer.nodeName, range.endOffset);
  console.log('Leer (collapsed)?', range.collapsed);
}
#text 4 #text 17 Leer (collapsed)? false

Auswahl innerhalb einer Web Component (Shadow DOM)

class NoteBox extends HTMLElement {
  #root = this.attachShadow({ mode: 'closed' });

  constructor() {
    super();
    this.#root.innerHTML = '<p>Markiere diesen Text im Shadow DOM.</p>';
    document.addEventListener('selectionchange', () => this.#report());
  }

  #report() {
    const sel = document.getSelection();
    // Nur mit übergebener Shadow Root liegen die Endpunkte im Shadow Tree
    const [range] = sel.getComposedRanges({ shadowRoots: [this.#root] });
    if (!range || range.collapsed) return;

    const inside = this.#root.contains(range.startContainer);
    console.log('Start im Shadow Tree:', inside);
  }
}

customElements.define('note-box', NoteBox);
document.body.append(document.createElement('note-box'));
Start im Shadow Tree: true

Vergleich: ohne shadowRoots wird auf den Host verschoben

const host = document.querySelector('note-box');
const sel = document.getSelection();

const [scoped] = sel.getComposedRanges();
// Endpunkte liegen jetzt beim Elternknoten des Hosts
console.log(scoped.startContainer === host.parentNode);
true

StaticRange in echten Range umwandeln und markierten Text lesen

const toLiveRange = (staticRange) => {
  const range = document.createRange();
  range.setStart(staticRange.startContainer, staticRange.startOffset);
  range.setEnd(staticRange.endContainer, staticRange.endOffset);
  return range;
};

const shadowRoot = document.querySelector('#editor').shadowRoot;
const [composed] = document.getSelection().getComposedRanges({ shadowRoots: [shadowRoot] });

if (composed) {
  const live = toLiveRange(composed);
  console.log('Markiert:', live.toString());
  console.log('Position:', live.getBoundingClientRect().top);
}
Markiert: Shadow DOM Position: 128

// Wichtig · Fallstricke

  • Signatur hat sich geändert: Ältere Umsetzungen, etwa Safari 17, erwarten die Shadow Roots als einzelne Argumente: getComposedRanges(root1, root2). Die aktuelle Spezifikation verlangt dagegen ein Objekt: getComposedRanges({ shadowRoots: [root1] }). Wer beide Formen unterstützen muss, sollte das Verhalten prüfen und bei Bedarf auf die alte Form ausweichen.
  • Browser-Unterstützung: Die Methode ist noch recht neu. Prüfen Sie vorher mit typeof Selection.prototype.getComposedRanges === 'function', ob sie vorhanden ist. Andernfalls greifen Sie auf getRangeAt(0) zurück.
  • Ohne shadowRoots keine Shadow-Knoten: Wer die Shadow Roots nicht übergibt, bekommt Endpunkte auf dem Shadow Host bzw. dessen Elternknoten. Das ist gewollt und schützt die Kapselung, wird aber oft für einen Fehler gehalten.
  • Statisch, nicht lebendig: StaticRange wird bei DOM-Änderungen nicht angepasst und kann danach auf ungültige Offsets zeigen. Werten Sie ihn also sofort aus oder wandeln Sie ihn in einen Range um.
  • Richtung: Wie bei getRangeAt() steht der Start immer vor dem Ende im Dokument. Ob der Nutzer rückwärts markiert hat, verrät Selection.direction.
  • Gibt es keine Auswahl, kommt ein leeres Array zurück. Es wird keine Ausnahme ausgelöst. Greifen Sie deshalb nicht ungeprüft auf ranges[0] zu.