From eb2855b1b7fb379f5996f98fbaf67a0cc3924509 Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Fri, 7 Aug 2026 10:53:51 -0700 Subject: [PATCH 1/2] fix: Scroll GridList to focused drop indicators Fixes #6492 --- .../react-aria-components/src/GridList.tsx | 1 + .../test/GridList.browser.test.tsx | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/packages/react-aria-components/src/GridList.tsx b/packages/react-aria-components/src/GridList.tsx index 22ea560aef6..f78c9c574be 100644 --- a/packages/react-aria-components/src/GridList.tsx +++ b/packages/react-aria-components/src/GridList.tsx @@ -769,6 +769,7 @@ function GridListDropIndicator(props: GridListDropIndicatorProps, ref: Forwarded let renderProps = useRenderProps({ ...otherProps, defaultClassName: 'react-aria-DropIndicator', + defaultStyle: {position: 'relative'}, values: { isDropTarget } diff --git a/packages/react-aria-components/test/GridList.browser.test.tsx b/packages/react-aria-components/test/GridList.browser.test.tsx index a8f13c11242..8cc6a88d062 100644 --- a/packages/react-aria-components/test/GridList.browser.test.tsx +++ b/packages/react-aria-components/test/GridList.browser.test.tsx @@ -10,6 +10,8 @@ * governing permissions and limitations under the License. */ +import {Button} from '../src/Button'; +import {DropIndicator, useDragAndDrop} from '../src/useDragAndDrop'; import {expect, it} from 'vitest'; import {GridLayout} from '../src/GridLayout'; import {GridList, GridListItem} from '../src/GridList'; @@ -17,8 +19,36 @@ import React, {useState} from 'react'; import {render} from 'vitest-browser-react'; import {Size} from 'react-stately/useVirtualizerState'; import {User} from '@react-aria/test-utils'; +import {userEvent} from 'vitest/browser'; import {Virtualizer} from '../src/Virtualizer'; +const reorderableItems = Array.from({length: 10}, (_, i) => ({id: i, name: `Item ${i}`})); + +function ReorderableGridList() { + let {dragAndDropHooks} = useDragAndDrop({ + getItems: keys => [...keys].map(key => ({'text/plain': String(key)})), + onReorder() {}, + renderDropIndicator: target => ( + + ) + }); + + return ( + + {item => ( + + + {item.name} + + )} + + ); +} + function Grid() { return ( { await button.click(); await expect(tester.getRows().length).toBeGreaterThan(0); }); + +it('scrolls focused drop indicators into view during keyboard reordering', async () => { + let {container} = await render(); + let gridlist = container.querySelector('[role=grid]') as HTMLElement; + let dragButton = container.querySelector('[aria-label="Drag Item 0"]') as HTMLElement; + dragButton.focus(); + + await userEvent.keyboard('{Enter}'); + + for (let i = 1; i <= 4; i++) { + await userEvent.keyboard('{ArrowDown}'); + let dropIndicator = document.activeElement as HTMLElement; + let indicatorRow = dropIndicator.closest('[role=row]') as HTMLElement; + let gridRect = gridlist.getBoundingClientRect(); + let indicatorRect = dropIndicator.getBoundingClientRect(); + + expect(dropIndicator).toHaveAttribute( + 'aria-label', + `Insert between Item ${i} and Item ${i + 1}` + ); + expect(dropIndicator).toHaveAttribute('role', 'button'); + expect(indicatorRow).toHaveStyle({ + backgroundColor: 'rgb(255, 0, 0)', + position: 'relative' + }); + expect(indicatorRect.top).toBeGreaterThanOrEqual(gridRect.top); + expect(indicatorRect.bottom).toBeLessThanOrEqual(gridRect.bottom); + } + + expect(gridlist.scrollTop).toBeGreaterThan(0); +}); From c3c13317605c54495c7a0c5854b07f90cec1065e Mon Sep 17 00:00:00 2001 From: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Date: Sat, 8 Aug 2026 07:32:12 -0700 Subject: [PATCH 2/2] test: fix lint violation and measure the indicator row in scroll assertion --- packages/react-aria-components/test/GridList.browser.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-aria-components/test/GridList.browser.test.tsx b/packages/react-aria-components/test/GridList.browser.test.tsx index 8cc6a88d062..4d5daa4c184 100644 --- a/packages/react-aria-components/test/GridList.browser.test.tsx +++ b/packages/react-aria-components/test/GridList.browser.test.tsx @@ -27,7 +27,7 @@ const reorderableItems = Array.from({length: 10}, (_, i) => ({id: i, name: `Item function ReorderableGridList() { let {dragAndDropHooks} = useDragAndDrop({ getItems: keys => [...keys].map(key => ({'text/plain': String(key)})), - onReorder() {}, + onReorder: () => undefined, renderDropIndicator: target => ( ) @@ -164,7 +164,7 @@ it('scrolls focused drop indicators into view during keyboard reordering', async let dropIndicator = document.activeElement as HTMLElement; let indicatorRow = dropIndicator.closest('[role=row]') as HTMLElement; let gridRect = gridlist.getBoundingClientRect(); - let indicatorRect = dropIndicator.getBoundingClientRect(); + let indicatorRect = indicatorRow.getBoundingClientRect(); expect(dropIndicator).toHaveAttribute( 'aria-label',