Skip to content

Focus the navigable region on Escape - #82310

Open
ellatrix wants to merge 8 commits into
trunkfrom
add/escape-navigates-regions
Open

Focus the navigable region on Escape#82310
ellatrix wants to merge 8 commits into
trunkfrom
add/escape-navigates-regions

Conversation

@ellatrix

@ellatrix ellatrix commented Sep 1, 2026

Copy link
Copy Markdown
Member

Context

Escape currently does nothing in the editor.

Tab on the over hand is overloaded. In some contexts it manipulates the content (indent), and otherwise it moves focus to the inspector. Quite confusing.

I would say resolving this conflict is blocking further progress on several iterations:

Additionally Tab can also easily be "trapped" by third party block that render editors like CodeMirror etc.

Solution

What would be the most natural key to press when being trapped? Escape, I'd say.

What if Escape moves focus to the navigable region (ARIA landmarks)? From there, it's so easy to get anywhere on the page: the block toolbar, inspector, header, publish panel, etc. This is currently quite clunky to get to with a hard to remember key combination. Once you Escape to a region, Tab and Shift+Tab can be used to cycle through these regions. Press Enter (or Escape) to... enter it. Escaping to a region can not only be used from the editor, but from anywhere.

I proposed this a while ago in #45157, but the feedback was that Escape is already used to switch back to browse mode in JAWS/NVDA. That's true, but I don't think it's a blocker. For people who use screen readers, it will simply take two Escape presses to navigate to the region, where the first press escapes the "focus mode" use for writing in blocks. When already in "browse mode", it just takes one press. On top of that, screen readers have their own dedicated keys to navigate regions/landmarks, so they have a lesser need of it.

It's also worth noting that the ARIA documentation prescribes nothing in terms of keyboard shortcuts to navigate landmark/regions. We have a very strange keyboard combination that is not standard at all, so there's nothing really to lose there.

Demo

region-navigation.mp4

With a screen reader, first NVDA with its Speech Viewer transcribing the announcements, then JAWS with its virtual cursor highlight. The extra first Escape is the screen reader leaving its typing mode; Escape then steps out, Tab visits every region by name, and Escape on the region goes back in, where typing resumes at the same spot:

region-navigation-screen-readers.mp4

Testing Instructions

  1. Click into a paragraph, press Escape: focus moves onto the Editor content region.
  2. Tab onwards through block toolbar, settings, publish, footer, top bar; Shift+Tab back.
  3. Enter on the content region: focus and caret return to where you left them.
  4. Escape still undoes an automatic change (type * ), closes popovers, and collapses a multi selection first.

New e2e coverage in test/e2e/specs/editor/various/escape-region-navigation.spec.js.

Written with the help of an AI assistant.

Pressing Escape anywhere inside a region moves focus onto the region
itself, and pressing it on a region cycles to the next one, backwards
with Shift. Anything that already handles the key, a popover, a modal,
the undo of an automatic change, the collapse of a multi selection,
keeps winning: the region navigation waits a microtask and only acts
when nothing else claimed the press, since listeners delegated at the
document level run after this handler within the same dispatch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

🤖 PR meta 🤖

📦 Bundle size

Size Change: +415 B (+0.01%)

Total Size: 8 MB

📦 View Changed
Filename Size Change
build/scripts/components/index.min.js 267 kB +415 B (+0.16%)

6cb25a1 Run

⚡ Performance

Show the results

Client side metrics exclude the server response time.

front-end-block-theme

Metric b454431 trunk % Change
timeToFirstByte 48.95 ms +12.16% -5.62% 49.15 ms +9.56% -8.95% -0.41%
largestContentfulPaint 80 ms +10% -7.5% 80 ms +7.5% -10% 0%
lcpMinusTtfb 28.55 ms +23.29% -5.78% 28.75 ms +18.26% -10.78% -0.7%
wpBeforeTemplate 23.35 ms +14.99% -6.12% 22.25 ms +18.16% -5.66% 4.94%
wpTemplate 21.62 ms +6.85% -2.54% 21.83 ms +9.21% -8.11% -0.96%
wpTotal 45.77 ms +9.59% -6.23% 45.87 ms +8.44% -9.4% -0.22%
wpMemoryUsage 7.54 MB +0% -0% 7.50 MB +0% -0% 0.45%
wpDbQueries 17 +0% -0% 17 +0% -0% 0%

front-end-classic-theme

Metric b454431 trunk % Change
timeToFirstByte 39.7 ms +11.46% -5.29% 39.85 ms +4.89% -2.76% -0.38%
largestContentfulPaint 78 ms +5.13% -2.56% 80 ms +2.5% -5% -2.5%
lcpMinusTtfb 38.7 ms +2.71% -4.39% 38.4 ms +3.91% -3.26% 0.78%
wpBeforeTemplate 19.24 ms +17.26% -3.69% 19.51 ms +6.87% -6.36% -1.38%
wpTemplate 16.47 ms +4.68% -4.19% 17.19 ms +3.14% -5.53% -4.19%
wpTotal 37.03 ms +9.69% -6.24% 36.86 ms +5.81% -3.23% 0.46%
wpMemoryUsage 6.16 MB +0% -0% 6.12 MB +0% -0% 0.57%
wpDbQueries 14 +0% -0% 14 +0% -0% 0%

media-processing

Metric b454431 trunk % Change
mediaProcessingJpeg 336.49 ms +2.16% -2.92% 334.61 ms +2.84% -1.13% 0.56%
mediaProcessingAvif 4939.18 ms +0.36% -0.26% 4948.35 ms +0.88% -0.8% -0.19%
mediaProcessingJpegToAvif 3456.05 ms +0.41% -0.23% 3442.62 ms +1.66% -0.21% 0.39%

media-upload

Metric b454431 trunk % Change
jpegUploadProcessing 1419.91 ms +1.13% -0.91% 1394.18 ms +0.42% -0.61% 1.85%
pngUploadProcessing 215.19 ms +27.21% -12.32% 178.73 ms +2.86% -2.16% 20.4%
largeJpegUploadProcessing 1401.54 ms +1.27% -0.72% 1397.28 ms +0.64% -0.44% 0.3%
multipleImageUploadProcessing 1458.64 ms +1.4% -1.17% 1474.73 ms +0.27% -0.43% -1.09%

post-editor

Metric b454431 trunk % Change
serverResponse 570.2 ms +1.3% -4.86% 552.9 ms +3.26% -2.29% 3.13%
firstPaint 257.11 ms +5.6% -14.17% 262.36 ms +29.98% -10.31% -2%
domContentLoaded 1345 ms +0.86% -0.87% 1352.87 ms +1.48% -0.84% -0.58%
loaded 1346.35 ms +0.86% -0.86% 1354.35 ms +1.48% -0.84% -0.59%
firstContentfulPaint 457.88 ms +1.29% -2.3% 447.15 ms +3.47% -2.19% 2.4%
firstBlock 3712.93 ms +0.97% -1.29% 3717.71 ms +1.54% -1.62% -0.13%
type 21.17 ms +7.84% -16.53% 22.88 ms +14.69% -12.98% -7.47%
typeWithoutInspector 21.22 ms +10.08% -17.11% 22.59 ms +15.76% -13.24% -6.06%
typeWithTopToolbar 24.77 ms +14.25% -8.4% 26.59 ms +12.79% -7.48% -6.84%
typeContainer 9.55 ms +8.8% -6.18% 10.52 ms +8.46% -5.7% -9.22%
focus 84.95 ms +23.31% -12.35% 95.95 ms +8.9% -4.96% -11.46%
firstFocus 185.09 ms +0% -0% 199.94 ms +0% -0% -7.43%
selectAll 628.16 ms +4.91% -0.4% 627.24 ms +6.11% -1.47% 0.15%
listViewOpen 69.64 ms +15.55% -2.76% 70.07 ms +15.21% -4.62% -0.61%
inserterOpen 23.55 ms +2.68% -4.37% 23.27 ms +6.1% -2.23% 1.2%
inserterHover 3.78 ms +10.32% -12.7% 3.7 ms +10% -3.78% 2.16%
inserterSearch 9.09 ms +10.89% -6.27% 9.08 ms +9.36% -12.67% 0.11%
loadPatterns 658.57 ms +1.76% -4.06% 673.56 ms +4.83% -6.58% -2.23%
wpTotal 560.43 ms +1.23% -4.88% 543.06 ms +3.19% -2.41% 3.2%
wpMemoryUsage 13.13 MB +0% -0% 13.10 MB +0% -0% 0.22%
wpDbQueries 53.5 +0.93% -0.93% 54 +0% -1.85% -0.93%

site-editor

Metric b454431 trunk % Change
serverResponse 547.2 ms +1.92% -5.03% 548.15 ms +2.53% -5.59% -0.17%
firstPaint 356.32 ms +23.41% -34.7% 298.26 ms +41.11% -15.07% 19.47%
domContentLoaded 1395.96 ms +1.85% -0.92% 1418.2 ms +1.28% -0.77% -1.57%
loaded 1397.31 ms +1.83% -0.92% 1419.5 ms +1.27% -0.76% -1.56%
firstContentfulPaint 439.59 ms +1.96% -1.63% 441.48 ms +6.22% -1.87% -0.43%
firstBlock 4464.37 ms +0.35% -0.75% 4540.43 ms +0.31% -1.01% -1.68%
type 20.11 ms +17.06% -12.08% 20.1 ms +15.12% -14.33% 0.05%
navigate 102.11 ms +9.57% -1.31% 107.98 ms +8.06% -4.41% -5.44%
loadPatterns 1565.81 ms +8.64% -9.32% 1350.24 ms +8.12% -2.51% 15.97%
loadPages 1305.56 ms +16.19% -11.56% 1252.37 ms +14.63% -5.62% 4.25%
wpTotal 538.03 ms +1.84% -5.13% 537.95 ms +2.63% -5.65% 0.01%
wpMemoryUsage 12.02 MB +0% -0% 11.99 MB +0% -0% 0.3%
wpDbQueries 43 +2.33% -0% 43 +2.33% -0% 0%

6cb25a1 Run

@github-actions github-actions Bot added the [Package] Components /packages/components label Sep 1, 2026
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ellatrix ellatrix mentioned this pull request Sep 1, 2026
72 tasks
Cycling with a closed panel landed focus on its empty region wrapper,
making the focus indicator vanish. Regions without a visible box are
skipped now. The floating block toolbar becomes a labelled region, so
the cycle reaches it right after the content, matching the original
regions proposal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added the [Package] Block editor /packages/block-editor label Sep 1, 2026
ellatrix and others added 2 commits September 1, 2026 15:55
At region level the page's focus stops are the regions, so Tab moves
between them and Shift+Tab back, wrapping at the ends. Enter goes into
the region: to the place focus last left it from, remembered when
Escape steps out, descending into same-origin frames, or to its first
tabbable. Escape on a region does nothing further; there is nowhere
higher. Entering a region moves off the wrapper, so the existing tests
that tabbed straight from a focused region into its content now press
Enter first.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The closed publish panel keeps only a toggle the region's own focus
reveals, so skipping regions by visible size alone removed it from the
cycle. A region is skipped only when it has no visible box and nothing
tabbable inside. The block toolbar floats over the content, preceding
it visually, so a region nested in another now comes before its
container in the cycle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ellatrix ellatrix added the [Type] Enhancement A suggestion for improvement. label Sep 2, 2026
The toolbar floats visibly inside the content region's focus outline, so
it follows the content in the cycle rather than preceding it. That is
plain document order for a nested region, so the reordering pass goes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ellatrix ellatrix changed the title Escape steps out to the surrounding editor region Focus the navigable region on Escape Sep 2, 2026
ellatrix and others added 2 commits September 1, 2026 19:10
The rule skipping regions without a visible box or anything tabbable is
gone. The shortcut cycle never filtered, and the one region it was
written around, the closed publish panel, belongs in the cycle anyway:
focusing it reveals its toggle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Escape stepped focus out onto the region, so pressing it again returns
to where focus came from. Same restore path as Enter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ellatrix
ellatrix marked this pull request as ready for review September 2, 2026 03:59
@ellatrix
ellatrix requested a review from a team as a code owner September 2, 2026 03:59
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: ellatrix <ellatrix@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Package] Block editor /packages/block-editor [Package] Components /packages/components [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant