Skip to content

Menu

import { Menu } from '@yarcl/react';
Last action: nothing yet
<Menu>
<Menu.Trigger>
<Button variant="outline">Actions</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item onSelect={rename}>Rename</Menu.Item>
<Menu.Item disabled>Move</Menu.Item>
<Menu.Separator />
<Menu.Item color="danger" onSelect={remove}>Delete</Menu.Item>
</Menu.Content>
</Menu>

Use Select for a form field. For a setting such as color scheme, use Menu.RadioGroup and Menu.RadioItem. Each item exposes role="menuitemradio" and aria-checked, with a check indicator beside the current choice. Choosing an item calls onValueChange and closes the menu. Keep the group’s value in state so it persists when the menu closes.

Menu.Trigger accepts a single element that passes through its props and ref. Use Button autoHeight for an avatar and two lines of text.

const [scheme, setScheme] = useState('system');
<Menu>
<Menu.Trigger>
<Button autoHeight variant="ghost">
<Avatar name="Ada Lovelace" />
<Stack gap="xs">
<Text>Ada Lovelace</Text>
<Text textStyle="caption" muted>ada@example.com</Text>
</Stack>
</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.RadioGroup aria-label="Color scheme" value={scheme} onValueChange={setScheme}>
<Menu.RadioItem value="light">Light</Menu.RadioItem>
<Menu.RadioItem value="dark">Dark</Menu.RadioItem>
<Menu.RadioItem value="system">System</Menu.RadioItem>
</Menu.RadioGroup>
</Menu.Content>
</Menu>

Radio items share action items’ arrow-key navigation, typeahead, disabled state, and focus return. Give the group a name with aria-label or aria-labelledby.

For route navigation from a menu action, see the router link recipe.

Key Action
Enter Space ↓ on the trigger opens the menu and focuses the first item
↑ ↓ moves between items, skipping disabled ones
typing jumps to a matching item
Enter Space runs the item and closes the menu
Esc closes; focus returns to the trigger

Style the panel and items with components.Menu.slots; see component parts. Menu.Content exposes data-part="panel"; items, including radio items, expose "item". Content is portaled, so put a scoping class directly on Menu.Content.

PropTypeDefaultDescription
childrenReactNodeMenu.Trigger and Menu.Content.
defaultOpenbooleanfalseInitial open state when uncontrolled.
onOpenChange(open: boolean) => voidCalled when the menu opens or closes.
openbooleanControlled open state.
placementPlacement'bottom-start'Preferred side. Flips when there isn't room.
size'lg' | 'xs' | 'sm' | 'md' | 'xl'config.defaults.sizeItem size, from the sizes config.
PropTypeDefaultDescription
colorColorconfigSemantic color for the item, e.g. a destructive action. From the colors config.
onSelect() => voidCalled when the item is chosen by click, Enter or Space. The menu closes afterwards. Calling preventDefault in onClick cancels selection and closing.
textValuestringText used for type-to-select. Defaults to children when it is a string.
PropTypeDefaultDescription
value requiredstring | nullControlled selected value. null means nothing is selected.
onValueChange(value: string) => voidCalled when a radio item is chosen.
PropTypeDefaultDescription
value requiredstringValue selected when this item is chosen.
aria-checkedundefined
colorColorconfigSemantic color for the item, e.g. a destructive action. From the colors config.
onSelect() => voidCalled when the item is chosen by click, Enter or Space. The menu closes afterwards. Calling preventDefault in onClick cancels selection and closing.
roleundefined
textValuestringText used for type-to-select. Defaults to children when it is a string.