Skip to content
Open
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ sync'd July 30, 2025
| IndexedDB: `getAllRecords()` | Shows the benefits of the proposed `getAllRecords()` IndexedDB method to more conveniently and quickly read IDB records. | [/idb-getallrecords/](https://github.com/MicrosoftEdge/Demos/tree/main/idb-getallrecords) | [IndexedDB: getAllRecords()](https://microsoftedge.github.io/Demos/idb-getallrecords/) demo |
| Notifications demo | Using incoming call notifications. | [/incoming-call-notifications/](https://github.com/MicrosoftEdge/Demos/tree/main/incoming-call-notifications) | [Notifications demo](https://microsoftedge.github.io/Demos/incoming-call-notifications/) |
| JSON dummy data | Simple JSON files. Used for [View a JSON file or server response with formatting](https://learn.microsoft.com/microsoft-edge/web-platform/json-viewer). | [/json-dummy-data/](https://github.com/MicrosoftEdge/Demos/tree/main/json-dummy-data) | [JSON dummy data](https://microsoftedge.github.io/Demos/json-dummy-data/) (Readme) |
| OpaqueRange | Demonstrates the `OpaqueRange` API for creating ranges over `<textarea>` and `<input>` values, enabling caret popup positioning and CSS Custom Highlight API usage on form controls. | [/opaque-range/](https://github.com/MicrosoftEdge/Demos/tree/main/opaque-range) | [OpaqueRange demo](https://microsoftedge.github.io/Demos/opaque-range/) |
| Page Colors Custom Scrollbars demo | Shows a custom, green scrollbar in a page that has custom colors. | [/page-colors-custom-scrollbars/](https://github.com/MicrosoftEdge/Demos/tree/main/page-colors-custom-scrollbars) | [Page Colors Custom Scrollbars demo](https://microsoftedge.github.io/Demos/page-colors-custom-scrollbars/) |
| Reference Target demos | Interactive demos of the Reference Target proposal, which allows ID references to cross shadow DOM boundaries. | [/reference-target/](https://github.com/MicrosoftEdge/Demos/tree/main/reference-target) | [Reference Target demos](https://microsoftedge.github.io/Demos/reference-target/) |
| Reader app | An article reader app used to demonstrate how to use various web APIs such as CSS Custom Highlight, `<selectmenu>`, EyeDropper, CSS and JSON modules, Scroll animation timeline, and Async Clipboard. | [/reader/](https://github.com/MicrosoftEdge/Demos/tree/main/reader) | [Reader](https://microsoftedge.github.io/Demos/reader/) demo |
Expand Down
22 changes: 22 additions & 0 deletions opaque-range/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# OpaqueRange

➡️ **[Open the demo](https://microsoftedge.github.io/Demos/opaque-range/)** ⬅️

`OpaqueRange` lets developers create live ranges over text inside `<input>` and `<textarea>` elements that automatically update as the user edits. These ranges support geometry methods like `getBoundingClientRect()` and the [CSS Custom Highlight API](https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API), enabling use cases like caret-positioned popups and inline search highlighting directly on form controls, without cloning elements or exposing internal DOM structure.

## Demos

- **Caret popup positioning** — Type `:` to trigger an emoji picker positioned at the caret
- **Search highlighting** — All occurrences of a search term are highlighted in real time using the CSS Custom Highlight API
- **Live range tracking** — Highlight "hello", then type before it and watch the highlight follow
- **Disconnecting a range** — Call `disconnect()` to detach a range and observe offsets reset to 0

## Learn more

- [Give feedback on the feature](https://github.com/MicrosoftEdge/MSEdgeExplainers/issues/new?template=opaque-range.md)
- [OpaqueRange explainer](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/OpaqueRange/explainer.md)
- [Origin Trial](https://developer.chrome.com/origintrials/#/register_trial/1731071106770534401)

## Requirements

The feature is experimental and not yet enabled by default in stable builds. It is available in Microsoft Edge 148 and other Chromium-based browsers version 148 and later. Sign up for the [Origin Trial](https://developer.chrome.com/origintrials/#/register_trial/1731071106770534401) to enable the feature without a flag. Otherwise, enable the **Experimental Web Platform features** flag at `about://flags` in Microsoft Edge or another Chromium-based browser.
118 changes: 118 additions & 0 deletions opaque-range/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpaqueRange demo</title>
<link rel="icon" type="image/png" href="https://edgestatic.azureedge.net/welcome/static/favicon.png">
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>OpaqueRange demo</h1>
<p>
The <code>OpaqueRange</code> API lets you create ranges over the value of
<code>&lt;textarea&gt;</code> and <code>&lt;input&gt;</code> elements, enabling
<code>getBoundingClientRect()</code> and the
<a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API">CSS Custom Highlight API</a>
to work directly on form controls without cloning elements.
<a href="https://github.com/MicrosoftEdge/MSEdgeExplainers/issues/new?template=opaque-range.md">Give feedback on the feature</a>.
</p>

<div id="feature-warning" class="warning" hidden>
<strong>⚠️ OpaqueRange is not supported in this browser.</strong>
OpaqueRange is available in Microsoft Edge 148 and other Chromium-based browsers version 148 and later.
Enable the <strong>Experimental Web Platform features</strong> flag at
<code>edge://flags</code> or <code>chrome://flags</code>, or sign up for the
<a href="https://developer.chrome.com/origintrials/#/register_trial/1731071106770534401">Origin Trial</a>.
</div>

<!-- Use Case 1: Caret Popup Positioning -->
<section class="demo-section">
<h2>Use case 1: Caret popup positioning</h2>
<p>
Type <kbd>:</kbd> in the textarea or the input field below to trigger an
emoji picker positioned at the caret.
</p>

<h3>Textarea</h3>
<div class="field-wrapper">
<textarea id="textarea-popup" rows="5" placeholder="Type : to show the emoji picker..."></textarea>
</div>

<h3>Input</h3>
<div class="field-wrapper">
<input type="text" id="input-popup" placeholder="Type : to show the emoji picker...">
</div>

<div id="mention-popup" class="popup" hidden>
<ul>
<li data-emoji="👍">👍 thumbs up</li>
<li data-emoji="❤️">❤️ heart</li>
<li data-emoji="😂">😂 laugh</li>
<li data-emoji="🎉">🎉 celebrate</li>
</ul>
</div>
</section>

<!-- Use Case 2: Search/Find Highlighting -->
<section class="demo-section">
<h2>Use case 2: Search highlighting</h2>
<p>
Type a search term in the search box below. All matching occurrences
in the textarea are highlighted in real time using the CSS Custom
Highlight API with <code>OpaqueRange</code>.
</p>

<div class="search-bar">
<label for="search-input">Search:</label>
<input type="text" id="search-input" placeholder="Type a word to find...">
<span id="search-count" class="info-text"></span>
</div>
<div class="field-wrapper">
<textarea id="textarea-search" rows="5">The quick brown fox jumps over the lazy dog. The dog barked at the fox, and the fox ran away.</textarea>
</div>
</section>

<!-- Use Case 3: Live Range -->
<section class="demo-section">
<h2>Use case 3: Live range tracking</h2>
<p>
<code>OpaqueRange</code> is live: it automatically updates its offsets as
the content changes via interactive edits (typing, backspace, delete) or
<code>setRangeText()</code>. Click <strong>Highlight "hello"</strong> to
highlight the word, then type before it and watch the highlight follow.
</p>

<div class="field-wrapper">
<textarea id="textarea-live" rows="3">hello world</textarea>
</div>
<div class="button-group">
<button id="btn-highlight-hello">Highlight "hello"</button>
<button id="btn-clear-live">Clear highlight</button>
</div>
<p id="live-range-info" class="info-text"></p>
</section>

<!-- Use Case 4: disconnect() -->
<section class="demo-section">
<h2>Use case 4: Disconnecting an OpaqueRange</h2>
<p>
Calling <code>range.disconnect()</code> detaches the range from its element.
The offsets reset to 0, geometry becomes empty, and the range stops
receiving live updates. Create a range, then disconnect it and observe the
change.
</p>

<div class="field-wrapper">
<textarea id="textarea-disconnect" rows="3">The quick brown fox</textarea>
</div>
<div class="button-group">
<button id="btn-create-range">Create range on "quick" (4–9)</button>
<button id="btn-disconnect-range">Disconnect range</button>
</div>
<p id="disconnect-info" class="info-text"></p>
</section>

<script src="script.js"></script>
</body>
</html>
Loading