Start · Sprachen · JavaScript · Referenz · Selection.focusOffset

Selection.focusOffset

Eigenschaft

Schreibgeschützte Zahl, die angibt, an welcher Position innerhalb von <code>Selection.focusNode</code> der Fokus (das bewegliche Ende) der Auswahl liegt.

seit JavaScript Baseline: alle Browser Kategorie: webapi

Signatur

Selection.focusOffset

Beschreibung

Die Eigenschaft focusOffset gibt die Position des Fokus einer Auswahl innerhalb ihres focusNode an. Der Fokus ist das Ende der Auswahl, an dem der Nutzer das Markieren beendet hat, also dort, wo die Maus losgelassen wurde oder wohin die Umschalttaste mit Pfeiltasten die Auswahl erweitert hat. Das Gegenstück dazu ist der Anker (anchorNode/anchorOffset).

Wie der Wert zu lesen ist, hängt vom Knotentyp ab:

  • Bei Text-, Comment- und CDATASection-Knoten ist es die Anzahl der Zeichen (UTF-16-Codeeinheiten) vor dem Fokus.
  • Bei Elementknoten ist es die Anzahl der Kindknoten vor dem Fokus.

Typische Einsatzfälle sind eigene Editoren, Erwähnungs- oder Autovervollständigungs-Funktionen in contenteditable-Bereichen, das Ermitteln der Cursorposition und Werkzeugleisten, die sich nach der Laufrichtung der Auswahl richten. Bei einer eingeklappten Auswahl (einem einfachen Cursor) sind focusOffset und anchorOffset gleich.

Rückgabewert

Typ
number
Beschreibung
Nicht negative Ganzzahl: bei Zeichendaten-Knoten die Zeichenposition, bei Elementen der Index des Kindknotens. Ohne Auswahl (rangeCount === 0) ist der Wert 0.

Beispiele

Fokusposition beim Markieren ausgeben

document.addEventListener('selectionchange', () => {
  const sel = document.getSelection();
  if (!sel || sel.rangeCount === 0) return;
  console.log('Fokus-Knoten:', sel.focusNode?.nodeName, 'Offset:', sel.focusOffset);
});
Fokus-Knoten: #text Offset: 12

Laufrichtung der Auswahl bestimmen

const isBackward = (sel) => {
  if (sel.isCollapsed) return false;
  if (sel.anchorNode === sel.focusNode) {
    return sel.focusOffset < sel.anchorOffset;
  }
  // DOCUMENT_POSITION_PRECEDING: Fokus liegt vor dem Anker
  return Boolean(
    sel.anchorNode.compareDocumentPosition(sel.focusNode) & Node.DOCUMENT_POSITION_PRECEDING
  );
};

document.addEventListener('mouseup', () => {
  const sel = window.getSelection();
  console.log(isBackward(sel) ? 'rückwärts markiert' : 'vorwärts markiert');
});
rückwärts markiert

Wort vor dem Cursor in contenteditable ermitteln (z. B. für @-Erwähnungen)

const editor = document.querySelector('[contenteditable]');

editor.addEventListener('input', () => {
  const sel = window.getSelection();
  const node = sel.focusNode;
  if (!sel.isCollapsed || node?.nodeType !== Node.TEXT_NODE) return;

  const textBefore = node.textContent.slice(0, sel.focusOffset);
  const match = textBefore.match(/@(\w*)$/);
  if (match) console.log('Erwähnung wird getippt:', match[1]);
});
Erwähnung wird getippt: ann

Fokus gezielt setzen und auslesen

const p = document.createElement('p');
p.textContent = 'Hallo Welt';
document.body.append(p);

const sel = window.getSelection();
sel.setBaseAndExtent(p.firstChild, 0, p.firstChild, 5);
console.log(sel.focusOffset, sel.toString());
5 Hallo

// Wichtig · Fallstricke

  • Schreibgeschützt: Eine Zuweisung an focusOffset hat keine Wirkung. Zum Verschieben des Fokus nutzt man Selection.extend(), setBaseAndExtent() oder collapse().
  • Knotentyp prüfen: Ist focusNode ein Element, ist der Wert ein Kindindex und keine Zeichenposition. Ein textContent.slice(0, focusOffset) liefert dann ein falsches Ergebnis.
  • Fokus ist nicht immer das Ende: Markiert der Nutzer rückwärts, liegt der Fokus vor dem Anker. Für Start und Ende in Dokumentreihenfolge verwendet man besser getRangeAt(0).startOffset/endOffset.
  • UTF-16: Der Offset zählt Codeeinheiten. Emojis und Zeichen außerhalb der BMP belegen daher 2 Einheiten.
  • Formularfelder: In <input> und <textarea> liefert focusOffset nicht die Cursorposition im Text. Dort sind selectionStart/selectionEnd zu verwenden.
  • Shadow DOM: Liegt die Auswahl in einem Shadow Tree, geben viele Browser den Host als focusNode zurück, und der Offset bezieht sich dann darauf. getComposedRanges() ist hier zuverlässiger, wird aber nicht überall unterstützt.
  • Die Eigenschaft wird von allen modernen Browsern unterstützt. Das Verhalten beim Markieren über Elementgrenzen hinweg kann sich zwischen den Browsern leicht unterscheiden.