Grid: fix keyboard activation on draggable items#78163
Conversation
|
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. |
|
Size Change: 0 B Total Size: 7.93 MB ℹ️ View Unchanged
|
|
Flaky tests detected in b936045. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/25678213135
|
|
Size Change: 0 B Total Size: 7.93 MB ℹ️ View Unchanged
|
73fff79 to
b936045
Compare
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
b936045 to
a905821
Compare
What?
Anchors the dnd-kit
useSortableattributesnext to itslistenerson the same element insideDashboardGridandDashboardLanesitems, and wiressetActivatorNodeRefso the keyboard sensor focuses the activator wrapper directly.Adds regression tests for both surfaces under
dashboard-grid/test/keyboard-activation.test.tsxanddashboard-lanes/test/keyboard-activation.test.tsx.Part of #77626 #77616
Why?
Each tile used to split the sortable bindings across two nested elements:
attributes(withtabIndex,role,aria-*) on the outer item,listeners(withonKeyDown) on an inner wrapper that also owned thegrabcursor.When the user tabbed to a tile, focus landed on the outer because of its
tabIndex. PressingSpacefiredkeydownon the focused outer element.React's synthetic events bubble up the ancestor chain from the target, never down to descendants, so the inner wrapper's
onKeyDownlistener never saw the event and the keyboard sensor's activation never fired. The Tab → Space → Arrow keys → Space drag, documented inpackages/grid/README.mdas supported, was broken in practice.How?
Moves
attributesto live on the same inner wrapper aslisteners, restoring the dnd-kit pattern where focus and keydown handlers share a node.The outer
.itemkeepssetNodeRefso dnd-kit measures the correct bounds for collision detection; the inner wrapper takessetActivatorNodeRefso the keyboard sensor and screen reader attributes target the focusable element.The original split existed so
actionableAreabuttons could render their own cursor (e.g.pointer) instead of inheriting the surface'sgrab. That goal is preserved:actionableAreastill sits outside the cursor-bearing wrapper, so its children keep their native cursors.Testing
Unit / structural
The new
keyboard-activation.test.tsxfiles render each surface in edit mode and assert that the dnd-kit activator (role="button",aria-roledescription="sortable") is nested inside the outer item, not on it. Reverting the fix flips the assertion:role="button"lands on the same node as the placement marker (data-lanes-keyon lanes, the inlinegrid-column-endstyle on grid) and the tests fail.Manual: before / after in Storybook
The base branch of this PR (
update/dashboard-masonry-layout) has aRevertcommit at HEAD that removes the fix, so checking out either branch flips between the two states without further setup.npm run storybook:dev. Open the URL it prints.Grid > DashboardGrid > Customization(turn oneditModein Controls)Grid > DashboardLanes > EditModeTabuntil a tile is focused (you should see a focus ring).Space. The tile should lift: the original becomes a dashed placeholder, and a clone follows the cursor in the drag overlay.Spaceto drop, orEscapeto cancel.Before
Screen.Recording.2026-05-11.at.10.04.58.AM.mov
After
Screen.Recording.2026-05-11.at.10.07.13.AM.mov