Start · Sprachen · JavaScript · Referenz · CaretPosition

CaretPosition

Schnittstelle

Beschreibt die Position des Text-Cursors (Caret) als Kombination aus DOM-Knoten und Offset. Man bekommt es über <code>document.caretPositionFromPoint()</code>.

seit JavaScript Firefox 20+, Chrome/Edge 128+; in Safari je nach V Kategorie: webapi

Signatur

interface CaretPosition

Beschreibung

Ein CaretPosition-Objekt beschreibt einen Einfügepunkt im Dokument, also die Stelle, an der der Text-Cursor stehen würde. Es hat keinen öffentlichen Konstruktor. Man bekommt es ausschließlich als Rückgabewert von document.caretPositionFromPoint(x, y), das zu Viewport-Koordinaten (z. B. aus einem Maus- oder Touch-Event) die nächstgelegene Caret-Position findet.

Das Interface stellt drei Mitglieder bereit:

  • offsetNode (Node, schreibgeschützt): Der Knoten, in dem die Caret-Position liegt, meistens ein Text-Knoten. Bei <input> und <textarea> ist es das Formularelement selbst.
  • offset (number, schreibgeschützt): Der Versatz innerhalb von offsetNode. Bei Textknoten ist das der Zeichenindex, bei Elementen der Index des Kindknotens. Bei Formularfeldern ist es der Index im value.
  • getClientRect(): Gibt ein DOMRect mit der Bildschirmposition des Carets zurück (bzw. null).

Typische Einsatzfälle sind: das Wort unter dem Mauszeiger ermitteln (Wörterbuch- oder Übersetzungs-Tooltips), Drag-&-Drop-Ziele genau innerhalb eines Textes bestimmen, eigene Editoren mit selbst gezeichnetem Caret oder das Einfügen von Markierungen an einer angeklickten Stelle. Aus offsetNode und offset lässt sich direkt ein Range oder eine Selection erzeugen.

Parameter

Name Typ Default Beschreibung
$x Pflicht number Parameter von document.caretPositionFromPoint(): horizontale Koordinate relativ zum Viewport (z. B. event.clientX).
$y Pflicht number Parameter von document.caretPositionFromPoint(): vertikale Koordinate relativ zum Viewport (z. B. event.clientY).
$options { shadowRoots?: ShadowRoot[] } {} Optional (neuere Spezifikation, Chrome 128+): Mit shadowRoots gibt man Shadow Roots an, in die hinein die Position aufgelöst werden darf. Ohne diese Angabe wird auf den Shadow Host umgebogen.

Rückgabewert

Typ
CaretPosition | null
Beschreibung
document.caretPositionFromPoint() gibt ein CaretPosition-Objekt zurück, oder null, wenn der Punkt außerhalb des Viewports liegt oder keine Position bestimmt werden kann.

Beispiele

Caret-Position per Klick ermitteln (mit Fallback)

// Liefert { node, offset } – nutzt caretRangeFromPoint als Fallback für ältere WebKit-/Chromium-Versionen
const getCaretAt = (x, y) => {
  if (document.caretPositionFromPoint) {
    const pos = document.caretPositionFromPoint(x, y);
    return pos ? { node: pos.offsetNode, offset: pos.offset } : null;
  }
  if (document.caretRangeFromPoint) {
    const range = document.caretRangeFromPoint(x, y);
    return range ? { node: range.startContainer, offset: range.startOffset } : null;
  }
  return null;
};

document.addEventListener('click', (event) => {
  const caret = getCaretAt(event.clientX, event.clientY);
  if (!caret) return;
  console.log(caret.node.nodeName, caret.offset);
});
#text 17

Wort unter dem Mauszeiger bestimmen

const wordAtPoint = (x, y) => {
  const pos = document.caretPositionFromPoint?.(x, y);
  if (!pos || pos.offsetNode.nodeType !== Node.TEXT_NODE) return null;

  const text = pos.offsetNode.textContent;
  let start = pos.offset;
  let end = pos.offset;
  // Nach links und rechts bis zur Wortgrenze laufen
  while (start > 0 && /\w/.test(text[start - 1])) start--;
  while (end < text.length && /\w/.test(text[end])) end++;
  return text.slice(start, end) || null;
};

document.addEventListener('dblclick', (e) => {
  console.log('Wort:', wordAtPoint(e.clientX, e.clientY));
});
Wort: JavaScript

Marker an der angeklickten Stelle einfügen

const article = document.querySelector('article');

article.addEventListener('click', (event) => {
  const pos = document.caretPositionFromPoint(event.clientX, event.clientY);
  if (!pos) return;

  // Range an der Caret-Position erzeugen und ein Element einfügen
  const range = document.createRange();
  range.setStart(pos.offsetNode, pos.offset);
  range.collapse(true);

  const marker = document.createElement('mark');
  marker.textContent = '▲';
  range.insertNode(marker);
});

Eigenes Caret mit getClientRect() zeichnen

const fakeCaret = document.createElement('div');
fakeCaret.className = 'fake-caret'; // Styling per CSS-Klasse: position: fixed; width: 2px; background: red;
document.body.append(fakeCaret);

document.addEventListener('mousemove', (e) => {
  const rect = document.caretPositionFromPoint?.(e.clientX, e.clientY)?.getClientRect();
  if (!rect) return;
  Object.assign(fakeCaret.style, {
    left: `${rect.left}px`,
    top: `${rect.top}px`,
    height: `${rect.height}px`
  });
});

// Wichtig · Fallstricke

  • Browser-Unterstützung: Firefox kann caretPositionFromPoint() schon lange, Chromium-Browser erst ab Version 128. Ältere Chrome-Versionen und viele Safari-Versionen haben nur das nicht standardisierte document.caretRangeFromPoint(), das einen Range zurückgibt. Man sollte also immer prüfen, ob die Funktion vorhanden ist, und eine Ausweichlösung einbauen.
  • Kein Konstruktor: new CaretPosition() wirft einen TypeError.
  • offsetNode ist nicht immer ein Textknoten: Bei Formularfeldern ist es das <input>- bzw. <textarea>-Element, und offset bezieht sich dann auf value. Bei Bildern oder leeren Elementen kann es ein Element sein, dann ist offset ein Index der Kindknoten. Vor Textoperationen deshalb nodeType prüfen.
  • Viewport-Koordinaten: Man muss clientX/clientY übergeben, nicht pageX/pageY. Punkte außerhalb des sichtbaren Bereichs ergeben null.
  • Shadow DOM: Ohne die Option shadowRoots wird die Position nicht in Shadow Trees hinein aufgelöst, sondern am Shadow Host gemeldet.
  • Momentaufnahme: Das Objekt wird nicht aktualisiert, wenn sich das DOM ändert. Nach DOM-Änderungen kann offset ungültig sein, was z. B. bei range.setStart() einen IndexSizeError auslöst.
  • Elemente mit pointer-events: none werden bei der Suche übersprungen.