Media Editor: Scope keyboard shortcuts to the modal#78322
Conversation
When the image editor modal is open, Ctrl+Z/Cmd+Z and other host editor shortcuts (`core/editor/undo`, `core/editor/redo`, `core/editor/save`, etc.) silently fire in the post editor underneath. React synthetic events bubble through the React parent tree — not the DOM tree — so key events from inside the portaled Modal still reach the host `ShortcutProvider` that the editor's `useShortcut` hooks listen on. Wrap the Modal in its own `ShortcutProvider` that stops React keydown propagation at the modal boundary. The Modal's existing handlers (frame `onKeyDown` for cropper undo, overlay Esc-to-close) sit deeper in the React tree and continue to run; native browser undo on metadata input fields is unaffected because `preventDefault` is still skipped for those targets.
|
Size Change: +57 B (0%) Total Size: 7.96 MB 📦 View Changed
ℹ️ View Unchanged
|
|
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 If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
There was a problem hiding this comment.
Pull request overview
Scopes the Media Editor modal's keyboard shortcuts to the modal itself by wrapping the Modal in a ShortcutProvider whose onKeyDown calls event.stopPropagation(). This prevents React synthetic keydown events from bubbling up the React tree (past the portal) to the host editor's ShortcutProvider, which was causing actions like Ctrl/Cmd+Z, redo, and save to fire in the underlying post editor.
Changes:
- Wrap the
Modalwith a newShortcutProviderthat stops React keydown propagation at the modal boundary. - Add
@wordpress/keyboard-shortcutsas a dependency of@wordpress/media-editor(package.json, tsconfig, lockfile).
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| packages/media-editor/src/components/media-editor-modal/index.tsx | Adds ShortcutProvider wrapper with a stopPropagation keydown handler around Modal. |
| packages/media-editor/package.json | Declares new @wordpress/keyboard-shortcuts dependency. |
| packages/media-editor/tsconfig.json | Adds project reference to ../keyboard-shortcuts. |
| package-lock.json | Reflects new workspace dependency. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
This is a targeted PR in an experiment. I'm going to land it. |
|
Flaky tests detected in fa80a18. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/25902134945
|
|
Yikes, great catch with this one! TIL |
What
When the image editor modal is open, host editor shortcuts (
Ctrl+Z/Cmd+Zundo, redo, save, etc.) still fire in the post editor underneath. So pressing Ctrl+Z to undo a crop also undoes the post — silently, since the modal covers the editor.This PR isolates the modal's keyboard events from the host editor.
2026-05-15.15.34.20.mp4
Why it happens
React synthetic events bubble through the React tree, not the DOM tree. So even though the Modal renders into
document.bodyvia a portal, a keydown inside the modal still bubbles up the React parent chain and reaches the editor'sShortcutProvider(the<div onKeyDown>that runs alluseShortcutcallbacks). The media editor's existinghandleKeyDownruns the cropper undo and callspreventDefault, but it neverstopPropagations — so the editor's undo fires too.How
Wrap the
<Modal>inmedia-editor-modal/index.tsxwith a new<ShortcutProvider>whoseonKeyDowncallsevent.stopPropagation(). The modal now has its own keyboard-shortcut scope, and React events stop at the modal boundary instead of climbing up to the host editor.Why this position works:
onKeyDownrunning the cropper undo, overlay handler running Esc-to-close) sit deeper in the React tree than our wrapper — they fire first, then propagation is stopped on the way out.stopPropagationonly affects React synthetic events. Browser-native undo on<input>/<textarea>fields is unaffected, because the existinghandleKeyDowncontinues to skippreventDefaultfor those targets.useShortcutcalls inside the modal.Testing
Open an image in the Media Editor modal from inside the post editor.
Before this PR, all of the Ctrl/Cmd+Z cases above would also undo the post in the background.