Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 102 additions & 5 deletions dom.bs
Original file line number Diff line number Diff line change
Expand Up @@ -4121,7 +4121,7 @@ dictionary MutationObserverInit {
or omitted.
</dl>

<dt><code><var>observer</var> . {{disconnect()}}</code>
<dt><code><var>observer</var> . {{MutationObserver/disconnect()}}</code>
<dd>Stops <var>observer</var> from observing any mutations. Until the {{observe()}} method is used
again, <var>observer</var>'s <a for=MutationObserver>callback</a> will not be invoked.

Expand Down Expand Up @@ -8669,9 +8669,9 @@ be between 0 and the <a>boundary point</a>'s <a for="boundary point">node</a>'s
<pre class=idl>
[Exposed=Window]
interface AbstractRange {
readonly attribute Node startContainer;
readonly attribute Node? startContainer;
readonly attribute unsigned long startOffset;
readonly attribute Node endContainer;
readonly attribute Node? endContainer;
readonly attribute unsigned long endOffset;
readonly attribute boolean collapsed;
};
Expand All @@ -8694,6 +8694,11 @@ interface AbstractRange {
<dfn export id=concept-range-end-offset for=range>end offset</dfn> is its <a for=range>end</a>'s
<a for="boundary point">offset</a>.

<p>A <a>range</a> has an associated <dfn export for=range id=concept-range-is-opaque>is opaque</dfn>
flag, initially false. When true, the {{AbstractRange/startContainer}} and
{{AbstractRange/endContainer}} getters return null. Only {{OpaqueRange}} objects have this flag set
to true.

<div algorithm>
<p>A <a>range</a> is <dfn for=range export>collapsed</dfn> if its <a for=range>start node</a> is its
<a for=range>end node</a> and its <a for=range>start offset</a> is its <a for=range>end offset</a>.
Expand All @@ -8719,7 +8724,8 @@ interface AbstractRange {
<div algorithm>
<p>The
<dfn id=dom-range-startcontainer attribute for=AbstractRange><code>startContainer</code></dfn>
getter steps are to return <a>this</a>'s <a for=range>start node</a>.
getter steps are to return null if <a>this</a>'s <a for=range>is opaque</a> flag is true; otherwise
<a>this</a>'s <a for=range>start node</a>.
</div>

<div algorithm>
Expand All @@ -8729,7 +8735,8 @@ getter steps are to return <a>this</a>'s <a for=range>start offset</a>.

<div algorithm>
<p>The <dfn id=dom-range-endcontainer attribute for=AbstractRange><code>endContainer</code></dfn>
getter steps are to return <a>this</a>'s <a for=range>end node</a>.
getter steps are to return null if <a>this</a>'s <a for=range>is opaque</a> flag is true; otherwise
<a>this</a>'s <a for=range>end node</a>.
</div>

<div algorithm>
Expand Down Expand Up @@ -9981,6 +9988,96 @@ and {{Range/getBoundingClientRect()}} methods are defined in other specification
[[CSSOM-VIEW]]


<h3 id=interface-opaquerange>Interface {{OpaqueRange}}</h3>

<pre class=idl>
[Exposed=Window]
interface OpaqueRange : AbstractRange {
undefined disconnect();
DOMRectList getClientRects();
DOMRect getBoundingClientRect();
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why OpaqueRange offsets are readonly? Or there isn't any method to update them?

Copy link
Copy Markdown
Author

@stephanieyzhang stephanieyzhang Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The offsets are readonly since they're inherited from AbstractRange. Currently the HTML PR defines createValueRange(start, end) on the element for creation. We haven't yet added an API for updating, so that's an open question. Some options could be an element-side API (e.g. updateValueRange(range, start, end)) to keep OpaqueRange generic, or setters directly on OpaqueRange.

Would appreciate your thoughts @annevk @smaug----

Comment thread
stephanieyzhang marked this conversation as resolved.
</pre>

<p>Objects implementing the {{OpaqueRange}} interface are known as {{OpaqueRange}} objects.
{{OpaqueRange}} objects cannot be constructed directly; they are created by specifications defining
elements that <a>support opaque ranges</a>.

<p>An {{OpaqueRange}} has an
<dfn export for=OpaqueRange>associated element</dfn> (an {{Element}} or null), initially null. It is
set by the specification that creates the {{OpaqueRange}}.

<dl class=domintro>
<dt><code><var ignore>range</var> . {{OpaqueRange/disconnect()}}</code>
<dd>Disconnects the range from its element and stops live updates. Afterwards, the range's
{{AbstractRange/startOffset}} and {{AbstractRange/endOffset}} are 0, and
{{OpaqueRange/getClientRects()}} and {{OpaqueRange/getBoundingClientRect()}} return empty results.
Calling this method on a range that is already disconnected has no effect.

<dt><code><var ignore>rects</var> = <var ignore>range</var> . {{OpaqueRange/getClientRects()}}</code>
<dd>Returns a {{DOMRectList}} of client rectangles that enclose the selected portion of the range.
If the user agent cannot compute geometry for the range (e.g. because the element it was created
from is not <a>connected</a> or has computed <code>display</code> of <code>none</code>), or if the
range is {{AbstractRange/collapsed}} with no visible caret, returns an empty list.

<dt><code><var ignore>rect</var> = <var ignore>range</var> . {{OpaqueRange/getBoundingClientRect()}}</code>
<dd>Returns a {{DOMRect}} that is the union of the rectangles from
{{OpaqueRange/getClientRects()}}. For a {{AbstractRange/collapsed}} range with a visible caret,
returns a rectangle of zero width whose height equals the line height at the caret position. If
the user agent cannot compute geometry for the range (e.g. because the element it was created
from is not <a>connected</a> or has computed <code>display</code> of <code>none</code>), returns
a rectangle with zero width and height.
</dl>

<div algorithm>
<p>The <dfn method for=OpaqueRange><code>disconnect()</code></dfn> method steps are:

<ol>
<li><p>Let <var>element</var> be <a>this</a>'s <a for=OpaqueRange>associated element</a>.

<li>
<p>If <var>element</var> is not null:

<ol>
<li><p>Run the <a>opaque range disconnect steps</a> given <var>element</var> and <a>this</a>.

<li><p>Set <a>this</a>'s <a for=OpaqueRange>associated element</a> to null.
</ol>

<li><p>Set <a>this</a>'s <a for=range>start offset</a> to 0.

<li><p>Set <a>this</a>'s <a for=range>end offset</a> to 0.
</ol>
</div>

<p>The {{OpaqueRange/getClientRects()}} and {{OpaqueRange/getBoundingClientRect()}} methods are
defined in [[CSSOM-VIEW]].

<p>An {{OpaqueRange}} is a <a>range</a> whose <a for=range>is opaque</a> flag is true.

<p>An {{Element}}
<dfn export id=supports-opaque-range>supports opaque ranges</dfn> if its specification defines that
it does. In HTML, this includes certain {{HTMLInputElement}} types and {{HTMLTextAreaElement}}.

<p class=note>Other specifications can designate additional elements, including custom elements.

<p>An {{OpaqueRange}} is live, meaning its offsets are automatically updated when the underlying
content changes. Specifications that define elements supporting opaque ranges must specify:

<ul>
<li><p>the internal container nodes used,

<li><p>how {{OpaqueRange}} objects are created and detached, and

<li><p><dfn export>opaque range update steps</dfn> to run when the underlying content changes
(e.g., when text is inserted or deleted). These steps should adjust offsets following the same
principles as the <a>live range</a> adjustments in the <a for=/>insert</a>, <a for=/>remove</a>,
<a>replace data</a>, and <a lt="split a Text node">split</a> algorithms.

<li><p><dfn export>opaque range disconnect steps</dfn>, given an element and an
{{OpaqueRange}}, to run when {{OpaqueRange/disconnect()}} is called.
</ul>


<h2 id="traversal">Traversal</h2>

Expand Down