From e1f4d8847726453762bd16a0918486c44eea4362 Mon Sep 17 00:00:00 2001 From: Daniel Lu Date: Tue, 18 Aug 2026 16:54:16 -0700 Subject: [PATCH 1/7] initial implementation of async menu, basically listbox implmentation --- packages/react-aria-components/src/Menu.tsx | 92 +++++++++++++++++++ .../stories/Menu.stories.tsx | 68 +++++++++++++- 2 files changed, 157 insertions(+), 3 deletions(-) diff --git a/packages/react-aria-components/src/Menu.tsx b/packages/react-aria-components/src/Menu.tsx index f88987a8ef9..b50d3ef51bb 100644 --- a/packages/react-aria-components/src/Menu.tsx +++ b/packages/react-aria-components/src/Menu.tsx @@ -22,6 +22,7 @@ import { BaseCollection, CollectionNode, ItemNode, + LoaderNode, SectionNode } from 'react-aria/private/collections/BaseCollection'; import { @@ -40,6 +41,7 @@ import { Provider, RenderProps, SlotProps, + StyleProps, StyleRenderProps, useContextProps, useRenderProps, @@ -79,7 +81,12 @@ import { } from '@react-types/shared'; import {FocusScope} from 'react-aria/FocusScope'; import {HeaderContext} from './Header'; +import {inertValue} from 'react-aria/private/utils/inertValue'; import {KeyboardContext} from './Keyboard'; +import { + LoadMoreSentinelProps, + useLoadMoreSentinel +} from 'react-aria/private/utils/useLoadMoreSentinel'; import {mergeProps} from 'react-aria/mergeProps'; import {MultipleSelectionState} from 'react-stately/useMultipleSelectionState'; import {Node} from '@react-types/shared'; @@ -631,3 +638,88 @@ export const MenuItem = /*#__PURE__*/ createLeafComponent(ItemNode, function Men ); }); + +export interface MenuLoadMoreItemProps + extends + Omit, + StyleProps, + DOMRenderProps<'div', undefined>, + GlobalDOMAttributes { + /** + * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the + * element. + * + * @default 'react-aria-MenuLoadMoreItem' + */ + className?: string; + /** + * The load more spinner to render when loading additional items. + */ + children?: ReactNode; + /** + * Whether or not the loading spinner should be rendered or not. + */ + isLoading?: boolean; +} + +export const MenuLoadMoreItem = createLeafComponent( + LoaderNode, + function MenuLoadingIndicator( + props: MenuLoadMoreItemProps, + ref: ForwardedRef, + item: Node + ) { + let state = useContext(MenuStateContext)!; + let {isLoading, onLoadMore, scrollOffset, ...otherProps} = props; + + let sentinelRef = useRef(null); + let memoedLoadMoreProps = useMemo( + () => ({ + onLoadMore, + collection: state?.collection, + sentinelRef, + scrollOffset + }), + [onLoadMore, scrollOffset, state?.collection] + ); + useLoadMoreSentinel(memoedLoadMoreProps, sentinelRef); + let renderProps = useRenderProps({ + ...otherProps, + id: undefined, + children: item.rendered, + defaultClassName: 'react-aria-MenuLoadingIndicator', + values: undefined + }); + + let itemProps = { + // For Android talkback + tabIndex: -1 + }; + + return ( + <> + {/* Always render the sentinel. For now onus is on the user for styling when using flex + gap (this would introduce a gap even though it doesn't take room) */} + {/* @ts-ignore - compatibility with React < 19 */} +
+
+
+ {isLoading && renderProps.children && ( + <> + {/* oxlint-disable jsx-a11y/role-has-required-aria-props -- loader row is not selectable */} + }> + {renderProps.children} + + + )} + + ); + } +); diff --git a/packages/react-aria-components/stories/Menu.stories.tsx b/packages/react-aria-components/stories/Menu.stories.tsx index 8c87e41a30c..91d710d09b0 100644 --- a/packages/react-aria-components/stories/Menu.stories.tsx +++ b/packages/react-aria-components/stories/Menu.stories.tsx @@ -13,18 +13,18 @@ import {action} from 'storybook/actions'; import {Button} from '../src/Button'; import {classNames} from '@adobe/react-spectrum/private/utils/classNames'; +import {Collection} from 'react-aria/Collection'; import {Header} from '../src/Header'; import {Heading} from '../src/Heading'; import {Input} from '../src/Input'; import {Keyboard} from '../src/Keyboard'; import {Label} from '../src/Label'; - import {ListLayout} from 'react-stately/useVirtualizerState'; - import { Menu, MenuItem, MenuItemProps, + MenuLoadMoreItem, MenuSection, MenuTrigger, SubmenuTrigger, @@ -32,13 +32,14 @@ import { } from '../src/Menu'; import {mergeProps} from 'react-aria/mergeProps'; import {Meta, StoryFn, StoryObj} from '@storybook/react'; -import {MyMenuItem} from './utils'; +import {LoadingSpinner, MyMenuItem} from './utils'; import {Popover} from '../src/Popover'; import React, {createContext, JSX, ReactElement, useContext} from 'react'; import {Separator} from '../src/Separator'; import styles from '../example/index.css'; import {Text} from '../src/Text'; import {TextField} from '../src/TextField'; +import {useAsyncList} from 'react-stately/useAsyncList'; import {Virtualizer} from '../src/Virtualizer'; import './styles.css'; @@ -649,3 +650,64 @@ export const UnavailableMenuItemExample: MenuStory = () => ( ); + +interface Character { + name: string; + height: number; + mass: number; + birth_year: number; +} + +export const MyMenuLoaderIndicator = props => { + return ( + + + + ); +}; + +// TODO: empty state support +export function AsyncMenu() { + let list = useAsyncList({ + async load({signal, cursor}) { + if (cursor) { + cursor = cursor.replace(/^http:\/\//i, 'https://'); + } + let res = await fetch(cursor || 'https://swapi.py4e.com/api/people/', {signal}); + let json = await res.json(); + return { + items: json.results, + cursor: json.next + }; + } + }); + + return ( + + + + + + {(item: Character) => {item.name}} + + + + + + ); +} From f27fe5f3b2fa0427958f3b23187785e23d732199 Mon Sep 17 00:00:00 2001 From: Daniel Lu Date: Thu, 20 Aug 2026 17:25:07 -0700 Subject: [PATCH 2/7] add empty state support --- .../react-aria-components/exports/index.ts | 2 + .../react-aria-components/src/GridList.tsx | 2 +- .../react-aria-components/src/ListBox.tsx | 2 +- packages/react-aria-components/src/Menu.tsx | 7 +- packages/react-aria-components/src/Table.tsx | 2 +- packages/react-aria-components/src/Tree.tsx | 3 +- .../stories/Menu.stories.tsx | 66 +++++++++++++++---- 7 files changed, 66 insertions(+), 18 deletions(-) diff --git a/packages/react-aria-components/exports/index.ts b/packages/react-aria-components/exports/index.ts index b9c568ddb9f..0b44dde22b4 100644 --- a/packages/react-aria-components/exports/index.ts +++ b/packages/react-aria-components/exports/index.ts @@ -148,6 +148,7 @@ export { export { Menu, MenuItem, + MenuLoadMoreItem, MenuTrigger, MenuSection, MenuContext, @@ -406,6 +407,7 @@ export type { MenuProps, MenuItemProps, MenuItemRenderProps, + MenuLoadMoreItemProps, MenuTriggerProps, SubmenuTriggerProps, MenuSectionProps diff --git a/packages/react-aria-components/src/GridList.tsx b/packages/react-aria-components/src/GridList.tsx index 22ea560aef6..dc767937f2d 100644 --- a/packages/react-aria-components/src/GridList.tsx +++ b/packages/react-aria-components/src/GridList.tsx @@ -827,7 +827,7 @@ export interface GridListLoadMoreItemProps * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the * element. * - * @default 'react-aria-GridListLoadMoreItem' + * @default 'react-aria-GridListLoadingIndicator' */ className?: string; /** diff --git a/packages/react-aria-components/src/ListBox.tsx b/packages/react-aria-components/src/ListBox.tsx index 55c8e8d9c5b..fdb06dd42da 100644 --- a/packages/react-aria-components/src/ListBox.tsx +++ b/packages/react-aria-components/src/ListBox.tsx @@ -726,7 +726,7 @@ export interface ListBoxLoadMoreItemProps * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the * element. * - * @default 'react-aria-ListBoxLoadMoreItem' + * @default 'react-aria-ListBoxLoadingIndicator' */ className?: string; /** diff --git a/packages/react-aria-components/src/Menu.tsx b/packages/react-aria-components/src/Menu.tsx index b50d3ef51bb..61f18c093dc 100644 --- a/packages/react-aria-components/src/Menu.tsx +++ b/packages/react-aria-components/src/Menu.tsx @@ -288,7 +288,7 @@ export interface MenuProps * @default 'react-aria-Menu' */ className?: ClassNameOrFunction; - /** Provides content to display when there are no items in the list. */ + /** Provides content to display when there are no items in the menu. */ renderEmptyState?: () => ReactNode; /** Whether the menu should close when the menu item is selected. */ shouldCloseOnSelect?: boolean; @@ -641,7 +641,7 @@ export const MenuItem = /*#__PURE__*/ createLeafComponent(ItemNode, function Men export interface MenuLoadMoreItemProps extends - Omit, + Omit, StyleProps, DOMRenderProps<'div', undefined>, GlobalDOMAttributes { @@ -649,7 +649,7 @@ export interface MenuLoadMoreItemProps * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the * element. * - * @default 'react-aria-MenuLoadMoreItem' + * @default 'react-aria-MenuLoadingIndicator' */ className?: string; /** @@ -717,6 +717,7 @@ export const MenuLoadMoreItem = createLeafComponent( ref={ref as ForwardedRef}> {renderProps.children} + {/* oxlint-enable jsx-a11y/role-has-required-aria-props */} )} diff --git a/packages/react-aria-components/src/Table.tsx b/packages/react-aria-components/src/Table.tsx index b4c8c9f3b8c..08ddd8b0cdc 100644 --- a/packages/react-aria-components/src/Table.tsx +++ b/packages/react-aria-components/src/Table.tsx @@ -2342,7 +2342,7 @@ export interface TableLoadMoreItemProps * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the * element. * - * @default 'react-aria-TableLoadMoreItem' + * @default 'react-aria-TableLoadingIndicator' */ className?: string; /** diff --git a/packages/react-aria-components/src/Tree.tsx b/packages/react-aria-components/src/Tree.tsx index 85e47c5aaa0..7165de7cff6 100644 --- a/packages/react-aria-components/src/Tree.tsx +++ b/packages/react-aria-components/src/Tree.tsx @@ -1075,7 +1075,7 @@ export interface TreeLoadMoreItemProps * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the * element. A function may be provided to compute the class based on component state. * - * @default 'react-aria-TreeLoadMoreItem' + * @default 'react-aria-TreeLoader' */ className?: ClassNameOrFunction; /** @@ -1124,6 +1124,7 @@ export const TreeLoadMoreItem = createLeafComponent(LoaderNode, function TreeLoa ...otherProps, id: undefined, children: item.rendered, + // TODO: this isn't consistent with other components defaultClassName: 'react-aria-TreeLoader', values: { level diff --git a/packages/react-aria-components/stories/Menu.stories.tsx b/packages/react-aria-components/stories/Menu.stories.tsx index 91d710d09b0..bb944bb5739 100644 --- a/packages/react-aria-components/stories/Menu.stories.tsx +++ b/packages/react-aria-components/stories/Menu.stories.tsx @@ -20,6 +20,7 @@ import {Input} from '../src/Input'; import {Keyboard} from '../src/Keyboard'; import {Label} from '../src/Label'; import {ListLayout} from 'react-stately/useVirtualizerState'; +import {LoadingSpinner, MyMenuItem} from './utils'; import { Menu, MenuItem, @@ -32,9 +33,8 @@ import { } from '../src/Menu'; import {mergeProps} from 'react-aria/mergeProps'; import {Meta, StoryFn, StoryObj} from '@storybook/react'; -import {LoadingSpinner, MyMenuItem} from './utils'; import {Popover} from '../src/Popover'; -import React, {createContext, JSX, ReactElement, useContext} from 'react'; +import React, {createContext, JSX, ReactElement, useContext, useRef} from 'react'; import {Separator} from '../src/Separator'; import styles from '../example/index.css'; import {Text} from '../src/Text'; @@ -658,7 +658,7 @@ interface Character { birth_year: number; } -export const MyMenuLoaderIndicator = props => { +const MyMenuLoaderIndicator = props => { return ( { ); }; -// TODO: empty state support -export function AsyncMenu() { +type AsyncMenuArgs = {delay: number; isEmpty: boolean}; + +function AsyncMenuRender(args: AsyncMenuArgs) { + let hasOpenedRef = useRef(false); + let list = useAsyncList({ async load({signal, cursor}) { + if (!hasOpenedRef.current) { + return {items: []}; + } if (cursor) { cursor = cursor.replace(/^http:\/\//i, 'https://'); } + await new Promise(resolve => setTimeout(resolve, args.delay)); let res = await fetch(cursor || 'https://swapi.py4e.com/api/people/', {signal}); let json = await res.json(); return { @@ -691,23 +698,60 @@ export function AsyncMenu() { } }); + let isLoading = list.loadingState === 'loading' || list.loadingState === 'loadingMore'; + return ( - + { + if (open && !hasOpenedRef.current && !args.isEmpty) { + hasOpenedRef.current = true; + list.reload(); + } + }}> ( +
+ {!args.isEmpty && isLoading ? ( + + ) : ( + 'No results' + )} +
+ )} onAction={action('onAction')}> - + {(item: Character) => {item.name}} - + {!args.isEmpty && ( + + )}
); } + +export const AsyncMenu: StoryObj = { + render: args => , + args: { + delay: 2000, + isEmpty: false + }, + argTypes: { + delay: { + control: 'number' + }, + isEmpty: { + control: 'boolean' + } + } +}; From 0406b49dd2375649babc0f5acfd06dc8f5a12961 Mon Sep 17 00:00:00 2001 From: Daniel Lu Date: Mon, 24 Aug 2026 16:47:17 -0700 Subject: [PATCH 3/7] add tests --- .../react-aria-components/test/Menu.test.tsx | 115 +++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/packages/react-aria-components/test/Menu.test.tsx b/packages/react-aria-components/test/Menu.test.tsx index ef2300d095d..08f903da97e 100644 --- a/packages/react-aria-components/test/Menu.test.tsx +++ b/packages/react-aria-components/test/Menu.test.tsx @@ -16,6 +16,7 @@ import { mockClickDefault, pointerMap, render, + setupIntersectionObserverMock, within } from '@react-spectrum/test-utils-internal'; import {AriaMenuTests} from './AriaMenu.test-util'; @@ -26,7 +27,15 @@ import {Heading} from '../src/Heading'; import {Input} from '../src/Input'; import {Keyboard} from '../src/Keyboard'; import {Label} from '../src/Label'; -import {Menu, MenuContext, MenuItem, MenuSection, MenuTrigger, SubmenuTrigger} from '../src/Menu'; +import { + Menu, + MenuContext, + MenuItem, + MenuLoadMoreItem, + MenuSection, + MenuTrigger, + SubmenuTrigger +} from '../src/Menu'; import {Popover} from '../src/Popover'; import {Pressable} from 'react-aria/Pressable'; import React, {useState} from 'react'; @@ -2089,6 +2098,110 @@ describe('Menu', () => { expect(document.activeElement).toBe(menuTester.getOptions()[0]); }); }); + + describe('async loading', () => { + let items = [{name: 'Foo'}, {name: 'Bar'}, {name: 'Baz'}]; + let renderEmptyState = () => { + return
empty state
; + }; + let AsyncMenu = (props: { + items?: typeof items; + isLoading?: boolean; + onLoadMore?: () => void; + }) => { + let {items, isLoading, onLoadMore} = props; + return ( + renderEmptyState()}> + + {item => {item.name}} + + + Loading... + + + ); + }; + + let onLoadMore = jest.fn(); + let observe = jest.fn(); + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.runAllTimers(); + jest.clearAllMocks(); + }); + + it('should render the loading element when isLoading is true', () => { + let tree = render(); + + let menu = tree.getByRole('menu'); + let menuTester = testUtilUser.createTester('Menu', {root: menu}); + let options = menuTester.getOptions({element: menu}); + expect(options).toHaveLength(4); + let loaderRow = options[3]; + expect(loaderRow).toHaveTextContent('Loading...'); + + let sentinel = tree.getByTestId('loadMoreSentinel'); + expect(sentinel.parentElement).toHaveAttribute('inert'); + }); + + it('should render the sentinel but not the loading indicator when not loading', () => { + let tree = render(); + + let menu = tree.getByRole('menu'); + let menuTester = testUtilUser.createTester('Menu', {root: menu}); + let options = menuTester.getOptions({element: menu}); + expect(options).toHaveLength(3); + expect(tree.queryByText('Loading...')).toBeFalsy(); + expect(tree.getByTestId('loadMoreSentinel')).toBeInTheDocument(); + }); + + it('should properly render the renderEmptyState if menu is empty', () => { + let tree = render(); + + let menu = tree.getByRole('menu'); + let menuTester = testUtilUser.createTester('Menu', {root: tree.getByRole('menu')}); + let options = menuTester.getOptions({element: menu}); + expect(options).toHaveLength(1); + expect(options[0]).toHaveTextContent('empty state'); + expect(tree.queryByText('Loading...')).toBeFalsy(); + expect(tree.getByTestId('loadMoreSentinel')).toBeInTheDocument(); + + // Setting isLoading will render the loader even if the menu is empty + tree.rerender(); + options = menuTester.getOptions({element: menu}); + expect(options).toHaveLength(2); + expect(options[1]).toHaveTextContent('empty state'); + expect(tree.queryByText('Loading...')).toBeTruthy(); + expect(tree.getByTestId('loadMoreSentinel')).toBeInTheDocument(); + }); + + it('should only fire onLoadMore when intersection is detected regardless of loading state', () => { + let observer = setupIntersectionObserverMock({observe}); + + let tree = render(); + let sentinel = tree.getByTestId('loadMoreSentinel'); + expect(observe).toHaveBeenLastCalledWith(sentinel); + expect(onLoadMore).toHaveBeenCalledTimes(0); + + act(() => { + observer.instance.triggerCallback([{isIntersecting: true}]); + }); + expect(onLoadMore).toHaveBeenCalledTimes(1); + observe.mockClear(); + + tree.rerender(); + expect(observe).toHaveBeenLastCalledWith(sentinel); + expect(onLoadMore).toHaveBeenCalledTimes(1); + + act(() => { + observer.instance.triggerCallback([{isIntersecting: true}]); + }); + expect(onLoadMore).toHaveBeenCalledTimes(2); + }); + }); }); // better to accept items from the test? or just have the test have a requirement that you render a certain-ish structure? From c1469badc807824d409970ef73b589bfe08a8057 Mon Sep 17 00:00:00 2001 From: Daniel Lu Date: Mon, 24 Aug 2026 17:10:39 -0700 Subject: [PATCH 4/7] add docs --- .../dev/s2-docs/pages/react-aria/Menu.mdx | 66 ++++++++++++++++++- .../react-aria-components/exports/Menu.ts | 2 + starters/docs/src/Menu.css | 8 +++ starters/docs/src/Menu.tsx | 11 ++++ 4 files changed, 86 insertions(+), 1 deletion(-) diff --git a/packages/dev/s2-docs/pages/react-aria/Menu.mdx b/packages/dev/s2-docs/pages/react-aria/Menu.mdx index f90d86cfcee..8b461aa285f 100644 --- a/packages/dev/s2-docs/pages/react-aria/Menu.mdx +++ b/packages/dev/s2-docs/pages/react-aria/Menu.mdx @@ -279,6 +279,52 @@ import {Button} from 'vanilla-starter/Button';
``` +### Asynchronous loading + +Use [renderEmptyState](#empty-state) to display a loading indicator during initial load. To enable infinite scrolling, render a `` at the end of the menu. Use whatever data fetching library you prefer — this example uses `useAsyncList` from `react-stately`. + +```tsx render +"use client"; +import {MenuTrigger, Menu, MenuItem, MenuLoadMoreItem} from 'vanilla-starter/Menu'; +import {Button} from 'vanilla-starter/Button'; +import {Collection} from 'react-aria-components/Collection'; +import {useAsyncList} from 'react-aria-components/useAsyncList'; + +interface Character { + name: string; + birth_year: string; +} + +function AsyncMenuExample() { + let list = useAsyncList({ + async load({signal, cursor}) { + if (cursor) cursor = cursor.replace(/^http:\/\//i, 'https://'); + let res = await fetch(cursor || 'https://swapi.py4e.com/api/people/', {signal}); + let json = await res.json(); + return {items: json.results, cursor: json.next}; + } + }); + + return ( + + + list.loadingState === 'loading' ? 'Loading…' : 'No characters found'}> + + {(item) => {item.name}} + + {/*- begin highlight -*/} + + {/*- end highlight -*/} + + + ); +} +``` + ### Links Use the `href` prop on a `` to create a link. @@ -313,6 +359,19 @@ By default, links are rendered as an `` element. Use the `render` prop to int } /> ``` +### Empty state + +```tsx render hideImports +"use client"; +import {Menu} from 'vanilla-starter/Menu'; + + 'No actions available.'}> + {[]} + +``` + ### Autocomplete Popovers can include additional components as siblings of a menu. This example uses an [Autocomplete](Autocomplete) with a [SearchField](SearchField) to let the user filter the items. @@ -559,7 +618,7 @@ import {Button} from 'react-aria-components/Button'; -```tsx links={{MenuTrigger: '#menutrigger', Button: 'Button', Popover: 'Popover', Menu: '#menu', MenuItem: '#menuitem', Separator: 'Separator', MenuSection: '#menusection', SubmenuTrigger: '#submenutrigger', SelectionIndicator: 'selection#animated-selectionindicator'}} +```tsx links={{MenuTrigger: '#menutrigger', Button: 'Button', Popover: 'Popover', Menu: '#menu', MenuItem: '#menuitem', Separator: 'Separator', MenuSection: '#menusection', SubmenuTrigger: '#submenutrigger', SelectionIndicator: 'selection#animated-selectionindicator', MenuLoadMoreItem: '#menuloadmoreitem'}} + list.loadingState === 'loading' ? 'Loading…' : 'No characters found'}> diff --git a/starters/hooks/src/Menu.css b/starters/hooks/src/Menu.css index b40c496357a..750260c730e 100644 --- a/starters/hooks/src/Menu.css +++ b/starters/hooks/src/Menu.css @@ -30,6 +30,14 @@ } } +.react-aria-MenuLoadingIndicator { + display: flex; + align-items: center; + justify-content: center; + height: 24px; + width: 100%; +} + .react-aria-MenuItem { margin-inline: var(--spacing-1); padding: calc((var(--spacing-8) - 1lh) / 2) 0; From e4862262eed7da19d0241e3c43f2f5d6c4985f11 Mon Sep 17 00:00:00 2001 From: Daniel Lu Date: Tue, 25 Aug 2026 10:37:44 -0700 Subject: [PATCH 6/7] hope this fixes it, cant run docs --- packages/dev/s2-docs/pages/react-aria/Menu.mdx | 16 ++++++++++------ starters/docs/src/Menu.css | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/dev/s2-docs/pages/react-aria/Menu.mdx b/packages/dev/s2-docs/pages/react-aria/Menu.mdx index 291403de5ab..5d87b859473 100644 --- a/packages/dev/s2-docs/pages/react-aria/Menu.mdx +++ b/packages/dev/s2-docs/pages/react-aria/Menu.mdx @@ -363,13 +363,17 @@ By default, links are rendered as an `` element. Use the `render` prop to int ```tsx render hideImports "use client"; -import {Menu} from 'vanilla-starter/Menu'; +import {MenuTrigger, Menu} from 'vanilla-starter/Menu'; +import {Button} from 'vanilla-starter/Button'; - 'No actions available.'}> - {[]} - + + + 'No actions available.'}> + {[]} + + ``` ### Autocomplete diff --git a/starters/docs/src/Menu.css b/starters/docs/src/Menu.css index 750260c730e..8dccb754d18 100644 --- a/starters/docs/src/Menu.css +++ b/starters/docs/src/Menu.css @@ -35,7 +35,7 @@ align-items: center; justify-content: center; height: 24px; - width: 100%; + grid-column: 1 / -1; } .react-aria-MenuItem { From d7f06b98fc7555f6634a20770b6d8ec3436cf6db Mon Sep 17 00:00:00 2001 From: Daniel Lu Date: Tue, 25 Aug 2026 10:59:34 -0700 Subject: [PATCH 7/7] fix build --- starters/hooks/src/Menu.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starters/hooks/src/Menu.css b/starters/hooks/src/Menu.css index 750260c730e..8dccb754d18 100644 --- a/starters/hooks/src/Menu.css +++ b/starters/hooks/src/Menu.css @@ -35,7 +35,7 @@ align-items: center; justify-content: center; height: 24px; - width: 100%; + grid-column: 1 / -1; } .react-aria-MenuItem {