← Chrome 152 reference

v152 · shipped · dom · text input

OpaqueRange

A new live range type for <textarea> and text <input> elements. Unlike DOM Range, an OpaqueRange operates over a form control's value text rather than DOM nodes — enabling getBoundingClientRect(), the CSS Highlights API, and anchored popovers for inline suggestions, AI autocomplete, and spell-check UIs.

Shipped in Chrome 152 OpaqueRange ships enabled by default in Chrome 152 (chromestatus milestone listing). It was in origin trial from Chrome 148; the API shape may still evolve in spec review. On Chrome 148–151, test with the #opaque-range flag.

at a glance

Shipped inChrome 152 (Enabled by default)
Origin trial fromChrome 148 (desktop, Android)
ExtendsAbstractRange (not Range)
Specwhatwg/dom PR #1404 (under active spec discussion; see also whatwg/html #10614 and the MSEdge OpaqueRange explainer)
ChromeStatus6297362687066112 — OpaqueRange

why it exists

Building inline-suggestion UI (AI autocomplete, spell-check, editor annotations) inside a <textarea> or <input> requires knowing the pixel position of a text offset in the control's value — but there is no standard API for that. Today developers work around this by mirroring the control's content into a hidden <div> overlay, measuring the clone, then positioning their UI relative to the clone. This is fragile and breaks whenever the control's font, padding, or scroll position differs from the mirror. OpaqueRange makes the browser do the geometry: create a range over value text offsets, call getBoundingClientRect(), and get the correct on-screen bounds. The range is live — its offsets stay valid as the value is edited.

Source: blink-dev Intent to Experiment — OpaqueRange.

shape of the API

[Exposed=Window]
interface OpaqueRange : AbstractRange {
  DOMRect getBoundingClientRect();
  DOMRectList getClientRects();
  undefined disconnect();
};

partial interface HTMLTextAreaElement {
  OpaqueRange createValueRange(unsigned long start, unsigned long end);
};

The createValueRange(start, end) method creates a live range over characters in the control's value. Offsets are 0-based character indices into the value string. If start > end, or if an offset exceeds the value length, the method throws an IndexSizeError DOMException. getBoundingClientRect() returns the union of client rects (or empty rect if not rendered or disconnected), getClientRects() returns line rects, and disconnect() stops tracking changes.

Source: whatwg/dom PR #1404; MSEdge OpaqueRange explainer.

examples

Creating an OpaqueRange

OpaqueRange objects are created via a new createValueRange() method on HTMLTextAreaElement and HTMLInputElement (text type):

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

// Create a range covering characters 4–12 in the textarea's value
const range = textarea.createValueRange(4, 12);

Getting geometry

// Returns the bounding rect of the text span in the control
const rect = range.getBoundingClientRect();

// Returns individual line-level rects (for multi-line spans)
const rects = range.getClientRects();

console.log('Text starts at:', rect.left, rect.top);

Using with the CSS Highlights API

// Highlight a range of value text (e.g., a misspelled word)
const range = textarea.createValueRange(7, 14);
const highlight = new Highlight(range);
CSS.highlights.set('spelling-error', highlight);

Live range behaviour and disconnect

const range = textarea.createValueRange(3, 8);

// User types at position 0 → range offsets update automatically
textarea.value = 'AB' + textarea.value;  // inserts at start
// range now covers the same original text at new positions

// Clean up range tracking when no longer needed
range.disconnect();
Source: blink-dev Intent to Ship — OpaqueRange; MSEdge OpaqueRange explainer.

browser support

BrowserSupport
ChromeChrome 152+ (enabled by default; origin trial Chrome 148–151)
EdgeEdge 152+ (origin trial 148–151)
FirefoxPositive signal (mozilla/standards-positions #1289)
SafariSupport signal (WebKit/standards-positions #541)

Security and privacy: OpaqueRange operates strictly on the value text of form controls that script already has access to. It encapsulates internal control DOM by returning null for startContainer and endContainer, preventing script from inspecting internal Shadow DOM structure of native inputs or textareas.

Source: chromestatus.com/feature/6297362687066112.

see also