Skip to content

feat: add webContents.caretBrowsingEnabled - #52696

Draft
snackzone wants to merge 2 commits into
electron:mainfrom
snackzone:zm-caret-browsing-api
Draft

feat: add webContents.caretBrowsingEnabled#52696
snackzone wants to merge 2 commits into
electron:mainfrom
snackzone:zm-caret-browsing-api

Conversation

@snackzone

@snackzone snackzone commented Aug 7, 2026

Copy link
Copy Markdown

Description of Change

Adds the ability to enable Chromium's Caret Browsing mode via webcontents.caretBrowsingEnabled, setCaretBrowsingEnabled(), and isCaretBrowsingEnabled(). Closes #31339.

Contributors guide: https://github.com/electron/electron/blob/main/CONTRIBUTING.md

Using a coding agent / AI? Read the policy: https://github.com/electron/governance/blob/main/policy/ai.md

NOTE: PRs submitted that do not follow this template will be automatically closed.
-->

Checklist

Release Notes

Notes: Added webContents.caretBrowsingEnabled for toggling caret browsing in a WebContents.

@welcome

welcome Bot commented Aug 7, 2026

Copy link
Copy Markdown

💖 Thanks for opening this pull request! 💖

Semantic PR titles

We use semantic commit messages to streamline the release process. Before your pull request can be merged, you should update your pull request title to start with a semantic prefix.

Examples of commit messages with semantic prefixes:

  • fix: don't overwrite prevent_default if default wasn't prevented
  • feat: add app.isPackaged() method
  • docs: app.isDefaultProtocolClient is now available on Linux

Commit signing

This repo enforces commit signatures for all incoming PRs.
To sign your commits, see GitHub's documentation on Telling Git about your signing key.

PR tips

Things that will help get your PR across the finish line:

  • Follow the JavaScript, C++, and Python coding style.
  • Run npm run lint locally to catch formatting errors earlier.
  • Document any user-facing changes you've made following the documentation styleguide.
  • Include tests when adding/changing behavior.
  • Include screenshots and animated GIFs whenever possible.

We get a lot of pull requests on this repo, so please be patient and we will get back to you as soon as we can.

@electron-cation electron-cation Bot added the new-pr 🌱 PR opened recently label Aug 7, 2026
Exposes the existing Blink renderer preference `caret_browsing_enabled`
as a settable property on webContents. Blink already applies this
preference on every renderer preferences sync, so toggling it takes
effect immediately without a reload.

Enables assistive-technology use cases that need a keyboard-navigable
caret in page content, which Chrome offers but Electron had no API for.

The specs arrow through non-editable prose rather than only reading the
preference back, because Blink honors the caret movement editor commands
in non-editable content only when caret browsing is on — so that is what
actually observes the renderer having received the preference.

Refs electron#31339

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@snackzone
snackzone force-pushed the zm-caret-browsing-api branch 3 times, most recently from 581c824 to 415bc00 Compare August 7, 2026 23:39
Blink draws and moves a caret once caret_browsing_enabled is set, but
assistive technology is never told, so a screen reader stays silent.
Notify ui::AXPlatform too, as Chrome does in
renderer_preferences_util.cc. It is process-wide while the preference is
per-WebContents, so refcount the instances that enable it.

* Caret attributes gate on AXPlatform::IsCaretBrowsingEnabled() before
  falling back to AXNode::HasVisibleCaretOrSelection(), which is false
  for a collapsed caret in non-editable content; untold, macOS reports
  NSNotFound and Windows never fires IA2_EVENT_TEXT_CARET_MOVED.
* A mirror would let one window disabling caret browsing degrade
  accessibility in another; Chrome's input is a uniform profile pref.
* Reconcile from a cached flag, before the preference-equality early
  return and at construction: a <webview> guest inherits the embedder's
  preferences via BrowserPluginGuest::InitInternal(), so a delta taken
  from the preference transition would release an uncounted reference.
* The destructor releases from the cached flag before its early returns,
  since web_contents() may be gone and the state must not stay pinned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@snackzone
snackzone force-pushed the zm-caret-browsing-api branch from 415bc00 to 261fdb3 Compare August 8, 2026 00:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new-pr 🌱 PR opened recently

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request]: Caret browsing from upstream Chromium

1 participant