From 3dda533b5381d05da42b30fac676484ab04e063f Mon Sep 17 00:00:00 2001 From: Reid Barber Date: Fri, 16 Jan 2026 16:54:27 -0600 Subject: [PATCH 1/2] fix(dnd): dispatch focusin on cancel to fix keyboard nav with no drop targets --- packages/@react-aria/dnd/src/DragManager.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/@react-aria/dnd/src/DragManager.ts b/packages/@react-aria/dnd/src/DragManager.ts index 2128797ffb4..ab306c65465 100644 --- a/packages/@react-aria/dnd/src/DragManager.ts +++ b/packages/@react-aria/dnd/src/DragManager.ts @@ -583,6 +583,9 @@ class DragSession { this.dragTarget.element.focus(); } + // Re-trigger focus event on active element, since it will not have received it during dragging (see cancelEvent). + document.activeElement?.dispatchEvent(new FocusEvent('focusin', {bubbles: true})); + announce(this.stringFormatter.format('dropCanceled')); } From 1159d33f847fc7a4f573a067c3858a49cb9e85dd Mon Sep 17 00:00:00 2001 From: Reid Barber Date: Fri, 16 Jan 2026 16:54:32 -0600 Subject: [PATCH 2/2] add story to test --- .../stories/Table.stories.tsx | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/packages/react-aria-components/stories/Table.stories.tsx b/packages/react-aria-components/stories/Table.stories.tsx index f33e05c8ac2..e30c0b75c58 100644 --- a/packages/react-aria-components/stories/Table.stories.tsx +++ b/packages/react-aria-components/stories/Table.stories.tsx @@ -529,6 +529,83 @@ DndTableExample.args = { isLoading: false }; +function DndTableWithNoValidDropTargetsRender(): JSX.Element { + let list = useListData({ + initialItems: [ + {id: '1', type: 'file', name: 'Adobe Photoshop'}, + {id: '2', type: 'file', name: 'Adobe XD'}, + {id: '3', type: 'folder', name: 'Documents'}, + {id: '4', type: 'file', name: 'Adobe InDesign'}, + {id: '5', type: 'folder', name: 'Utilities'}, + {id: '6', type: 'file', name: 'Adobe AfterEffects'} + ] + }); + + let {dragAndDropHooks} = useDragAndDrop({ + getItems(keys) { + return [...keys].filter(k => !!list.getItem(k)).map((key) => { + let item = list.getItem(key); + return { + 'custom-app-type': JSON.stringify(item), + 'text/plain': item!.name + }; + }); + }, + onItemDrop() {}, + shouldAcceptItemDrop() { + return false; + } + }); + + return ( + + + + + ID + Name + Type + + + + {item => ( + + + + {item.id} + {item.name} + {item.type} + + )} + + +
+ ); +} + +export const DndTableWithNoValidDropTargets: TableStoryObj = { + render: DndTableWithNoValidDropTargetsRender, + name: 'Dnd Table with no valid drop targets', + parameters: { + description: { + data: `Tests that arrow keys work after canceling a keyboard drag when shouldAcceptItemDrop rejects all drop targets. + Test Instructions: + 1. Focus on an item's drag button + 2. Press Enter to start keyboard drag + 3. Notice there are no valid drop targets (shouldAcceptItemDrop rejects all item drops) + 4. Press Escape to cancel the drag + 5. Try pressing arrow keys + 6. Observe that focus moves (and we've exited virtual drag mode) + ` + } + } +}; + export const MyCheckbox = ({children, ...props}: CheckboxProps) => { return (