Signatur
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 einText-Knoten. Bei<input>und<textarea>ist es das Formularelement selbst.offset(number, schreibgeschützt): Der Versatz innerhalb vonoffsetNode. Bei Textknoten ist das der Zeichenindex, bei Elementen der Index des Kindknotens. Bei Formularfeldern ist es der Index imvalue.getClientRect(): Gibt einDOMRectmit 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
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);
});
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));
});
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 standardisiertedocument.caretRangeFromPoint(), das einenRangezurückgibt. Man sollte also immer prüfen, ob die Funktion vorhanden ist, und eine Ausweichlösung einbauen. - Kein Konstruktor:
new CaretPosition()wirft einenTypeError. offsetNodeist nicht immer ein Textknoten: Bei Formularfeldern ist es das<input>- bzw.<textarea>-Element, undoffsetbezieht sich dann aufvalue. Bei Bildern oder leeren Elementen kann es ein Element sein, dann istoffsetein Index der Kindknoten. Vor Textoperationen deshalbnodeTypeprüfen.- Viewport-Koordinaten: Man muss
clientX/clientYübergeben, nichtpageX/pageY. Punkte außerhalb des sichtbaren Bereichs ergebennull. - Shadow DOM: Ohne die Option
shadowRootswird 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
offsetungültig sein, was z. B. beirange.setStart()einenIndexSizeErrorauslöst. - Elemente mit
pointer-events: nonewerden bei der Suche übersprungen.