Menu

Displays a menu to the user, such as a set of actions or functions, triggered by a button.

Usage

1import { Menu } from '@raystack/apsara'

API Reference

The Menu component is composed of several parts, each with their own props.

Root

The root element is the parent component that holds the menu. Using the autocomplete prop, you can enable search functionality.

Prop

Type

Trigger

The button that triggers the menu.

By default, the click event is not propagated. You can override this behavior by passing stopPropagation={false}.

Use the render prop to render a custom trigger element.

Prop

Type

Content

The container that holds the menu items. When autocomplete is enabled, renders an inline search input inside the popup with a search input.

Prop

Type

Item

Individual clickable options within the menu. Built on top of Base UI Menu.Item.

Renders as a role='option'when used in an autocomplete menu. By default, the item's children text content is used for matching, which can be overridden by passing a value prop.

Prop

Type

Group

A way to group related menu items together. When filtering is active, the group wrapper is removed and items are rendered flat.

Prop

Type

Label

Renders a label in a menu group. This component should be wrapped with Menu.Group so the aria-labelledby is correctly set on the group element. Hidden when filtering is active.

Prop

Type

Separator

Visual divider between menu items or groups. Hidden when filtering is active.

Prop

Type

EmptyState

Placeholder content when there are no menu items to display.

Prop

Type

Wraps a submenu root. Use with Menu.SubmenuTrigger and Menu.SubmenuContent to create nested menus.

Supports its own autocomplete prop to enable search functionality within the submenu independently from the parent menu.

Prop

Type

The trigger item for a submenu. Renders with a trailing chevron icon by default. Accepts leadingIcon and trailingIcon props.

When inside a searchable parent menu, the value prop can be used for autocomplete matching.

Prop

Type

The content container for a submenu. Shares the same API as Menu.Content with a default sideOffset of 2.

Prop

Type

Examples

Basic Usage

A simple menu with basic functionality.

1<Menu>
2 <Menu.Trigger render={<Button color="neutral" />}>Open Menu</Menu.Trigger>
3 <Menu.Content>
4 <Menu.Item>Profile</Menu.Item>
5 <Menu.Item>Settings</Menu.Item>
6 <Menu.Separator />
7 <Menu.Item>Logout</Menu.Item>
8 </Menu.Content>
9</Menu>

With Icons

You can add icons to the menu items. Supports both leading and trailing icons.

1<Menu>
2 <Menu.Trigger render={<Button color="neutral" />}>Actions</Menu.Trigger>
3 <Menu.Content>
4 <Menu.Item leadingIcon={<>📝</>}>Edit</Menu.Item>
5 <Menu.Item leadingIcon={<>📋</>} trailingIcon={<>⌘C</>}>
6 Copy
7 </Menu.Item>
8 <Menu.Separator />
9 <Menu.Item leadingIcon={<>🗑️</>}>Delete</Menu.Item>
10 </Menu.Content>
11</Menu>

With Groups and Labels

Organize related menu items into sections with descriptive headers.

1<Menu>
2 <Menu.Trigger render={<Button color="neutral" />}>More</Menu.Trigger>
3 <Menu.Content>
4 <Menu.Group>
5 <Menu.Label>Actions</Menu.Label>
6 <Menu.Item>New File</Menu.Item>
7 <Menu.Item>New Folder</Menu.Item>
8 </Menu.Group>
9 <Menu.Separator />
10 <Menu.Group>
11 <Menu.Label>Sort By</Menu.Label>
12 <Menu.Item>Name</Menu.Item>
13 <Menu.Item>Date</Menu.Item>
14 </Menu.Group>
15 </Menu.Content>

Use Menu.Submenu, Menu.SubmenuTrigger, and Menu.SubmenuContent to create nested menus with multiple levels.

1<Menu>
2 <Menu.Trigger render={<Button color="neutral" />}>Basic Menu</Menu.Trigger>
3 <Menu.Content>
4 <Menu.Item>Profile</Menu.Item>
5 <Menu.Item>Settings</Menu.Item>
6 <Menu.Separator />
7 <Menu.Item>Logout</Menu.Item>
8 <Menu.Submenu>
9 <Menu.SubmenuTrigger>Sub Menu</Menu.SubmenuTrigger>
10 <Menu.SubmenuContent>
11 <Menu.Item>Sub Menu Item 1</Menu.Item>
12 <Menu.Item>Sub Menu Item 2</Menu.Item>
13 <Menu.Item>Sub Menu Item 3</Menu.Item>
14 </Menu.SubmenuContent>
15 </Menu.Submenu>

Autocomplete

To enable autocomplete, pass the autocomplete prop to the Menu root element. Each menu instance will manage its own autocomplete behavior.

By default (autocompleteMode="auto"), items are automatically filtered as the user types. The filter matches against the item's value prop or its children text content.

For submenus, you can independently enable autocomplete by passing autocomplete to Menu.Submenu.

For more advanced control, set autocompleteMode="manual" and implement your own custom filtering logic using the onInputValueChange callback.

1<Menu autocomplete>
2 <Menu.Trigger render={<Button color="neutral" />}>
3 Default Autocomplete
4 </Menu.Trigger>
5 <Menu.Content searchPlaceholder="Search">
6 <Menu.Group>
7 <Menu.Label>Heading</Menu.Label>
8 <Menu.Item>Assign member...</Menu.Item>
9 <Menu.Item>Subscribe...</Menu.Item>
10 <Menu.Item>Rename...</Menu.Item>
11 </Menu.Group>
12 <Menu.Separator />
13 <Menu.Group>
14 <Menu.Label>Actions</Menu.Label>
15 <Menu.Submenu>

Linear inspired Menu

This is a Linear-inspired menu component that supports custom filtering and displays nested options. Users can search through all nested items using a single input field.

To closely replicate Linear-style filtering, the filtering logic should include result ranking. Using a utility like match-sorter can help achieve this by sorting filtered results based on relevance.

1(function LinearMenuDemo() {
2 const [searchQuery, setSearchQuery] = useState("");
3
4 const renderMenu = (items: MenuItem[], query: string) => {
5 const filteredItems = filterMenuItems(items, query);
6
7 if (searchQuery && filteredItems.length === 0) {
8 return <div className="no-results">No results</div>;
9 }
10
11 return filteredItems.map((item, index) => {
12 switch (item.type) {
13 case "group":
14 return (
15 <Menu.Group key={index}>