'use client'
import { Button, Menu } from '@saas-ui/react'
export const MenuBasic = () => {
return (
<Menu.Root>
<Menu.Trigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="new-txt">New Text File</Menu.Item>
<Menu.Item value="new-file">New File...</Menu.Item>
<Menu.Item value="new-win">New Window</Menu.Item>
<Menu.Item value="open-file">Open File...</Menu.Item>
<Menu.Item value="export">Export</Menu.Item>
</Menu.Content>
</Menu.Root>
)
}
import { Menu } from '@saas-ui/react/menu'
<Menu.Root>
<Menu.Button />
<Menu.Content>
<Menu.Item value="item" />
</Menu.Content>
</Menu.Root>
Use the MenuItemCommand
component to display a command in the menu.
'use client'
import { Button, Menu } from '@saas-ui/react'
export const MenuWithCommand = () => {
return (
<Menu.Root>
<Menu.Trigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="new-txt-a">
New Text File <Menu.ItemCommand>⌘E</Menu.ItemCommand>
</Menu.Item>
<Menu.Item value="new-file-a">
New File... <Menu.ItemCommand>⌘N</Menu.ItemCommand>
</Menu.Item>
<Menu.Item value="new-win-a">
New Window <Menu.ItemCommand>⌘⇧N</Menu.ItemCommand>
</Menu.Item>
<Menu.Item value="open-file-a">
Open File... <Menu.ItemCommand>⌘O</Menu.ItemCommand>
</Menu.Item>
<Menu.Item value="export-a">
Export <Menu.ItemCommand>⌘S</Menu.ItemCommand>
</Menu.Item>
</Menu.Content>
</Menu.Root>
)
}
Use the MenuContextTrigger
component to create a context menu.
'use client'
import { Center } from '@chakra-ui/react'
import { Menu } from '@saas-ui/react'
export const MenuWithContextTrigger = () => {
return (
<Menu.Root>
<Menu.ContextTrigger w="full">
<Center
width="full"
height="40"
userSelect="none"
borderWidth="2px"
borderStyle="dashed"
rounded="lg"
padding="4"
>
Right click here
</Center>
</Menu.ContextTrigger>
<Menu.Content>
<Menu.Item value="new-txt">New Text File</Menu.Item>
<Menu.Item value="new-file">New File...</Menu.Item>
<Menu.Item value="new-win">New Window</Menu.Item>
<Menu.Item value="open-file">Open File...</Menu.Item>
<Menu.Item value="export">Export</Menu.Item>
</Menu.Content>
</Menu.Root>
)
}
Use the MenuItemGroup
component to group related menu items.
'use client'
import { Button, Menu } from '@saas-ui/react'
export const MenuWithGroup = () => {
return (
<Menu.Root>
<Menu.Trigger asChild>
<Button variant="outline">Edit</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.ItemGroup title="Styles">
<Menu.Item value="bold">Bold</Menu.Item>
<Menu.Item value="underline">Underline</Menu.Item>
</Menu.ItemGroup>
<Menu.Separator />
<Menu.ItemGroup title="Align">
<Menu.Item value="left">Left</Menu.Item>
<Menu.Item value="middle">Middle</Menu.Item>
<Menu.Item value="right">Right</Menu.Item>
</Menu.ItemGroup>
</Menu.Content>
</Menu.Root>
)
}
Here's an example of how to create a submenu.
'use client'
import { Button, Menu } from '@saas-ui/react'
export const MenuWithSubmenu = () => {
return (
<Menu.Root>
<Menu.Trigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="new-txt">New Text File</Menu.Item>
<Menu.Item value="new-file">New File...</Menu.Item>
<Menu.Root positioning={{ placement: 'right-start', gutter: 2 }}>
<Menu.TriggerItem value="open-recent">Open Recent</Menu.TriggerItem>
<Menu.Content>
<Menu.Item value="panda">Panda</Menu.Item>
<Menu.Item value="ark">Ark UI</Menu.Item>
<Menu.Item value="chakra">Chakra v3</Menu.Item>
</Menu.Content>
</Menu.Root>
<Menu.Item value="open-file">Open File...</Menu.Item>
<Menu.Item value="export">Export</Menu.Item>
</Menu.Content>
</Menu.Root>
)
}
Pass the asChild
prop to the MenuItem
component to render a link.
'use client'
import { Button, Menu } from '@saas-ui/react'
export const MenuWithLinks = () => {
return (
<Menu.Root>
<Menu.Trigger asChild>
<Button size="sm" variant="outline">
Select Anime
</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item asChild value="naruto">
<a
href="https://www.crunchyroll.com/naruto"
target="_blank"
rel="noreferrer"
>
Naruto
</a>
</Menu.Item>
<Menu.Item asChild value="one-piece">
<a
href="https://www.crunchyroll.com/one-piece"
target="_blank"
rel="noreferrer"
>
One Piece
</a>
</Menu.Item>
<Menu.Item asChild value="attack-on-titan">
<a
href="https://www.crunchyroll.com/attack-on-titan"
target="_blank"
rel="noreferrer"
>
Attack on Titan
</a>
</Menu.Item>
</Menu.Content>
</Menu.Root>
)
}
Here's an example of how to create a menu with radio.
'use client'
import { useState } from 'react'
import { Button, Menu } from '@saas-ui/react'
import { HiSortAscending } from 'react-icons/hi'
export const MenuWithRadioItems = () => {
const [value, setValue] = useState('asc')
return (
<Menu.Root>
<Menu.Trigger asChild>
<Button variant="outline" size="sm">
<HiSortAscending /> Sort
</Button>
</Menu.Trigger>
<Menu.Content minW="10rem">
<Menu.RadioItemGroup
value={value}
onValueChange={(e) => setValue(e.value)}
>
<Menu.RadioItem value="asc">Ascending</Menu.RadioItem>
<Menu.RadioItem value="desc">Descending</Menu.RadioItem>
</Menu.RadioItemGroup>
</Menu.Content>
</Menu.Root>
)
}
Compose the menu to include icons and commands.
'use client'
import { Box } from '@chakra-ui/react'
import { Button, Menu } from '@saas-ui/react'
import { LuClipboardPaste, LuCopy, LuScissors } from 'react-icons/lu'
export const MenuWithIconAndCommand = () => {
return (
<Menu.Root>
<Menu.Trigger asChild>
<Button variant="outline">Edit</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="cut" valueText="cut">
<LuScissors />
<Box flex="1">Cut</Box>
<Menu.ItemCommand>⌘X</Menu.ItemCommand>
</Menu.Item>
<Menu.Item value="copy" valueText="copy">
<LuCopy />
<Box flex="1">Copy</Box>
<Menu.ItemCommand>⌘C</Menu.ItemCommand>
</Menu.Item>
<Menu.Item value="paste" valueText="paste">
<LuClipboardPaste />
<Box flex="1">Paste</Box>
<Menu.ItemCommand>⌘V</Menu.ItemCommand>
</Menu.Item>
</Menu.Content>
</Menu.Root>
)
}
Use the positioning.placement
prop to control the placement of the menu.
'use client'
import { Button, Menu } from '@saas-ui/react'
export const MenuWithPlacement = () => {
return (
<Menu.Root positioning={{ placement: 'right-start' }}>
<Menu.Trigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="new-txt">New Text File</Menu.Item>
<Menu.Item value="new-file">New File...</Menu.Item>
<Menu.Item value="new-win">New Window</Menu.Item>
<Menu.Item value="open-file">Open File...</Menu.Item>
<Menu.Item value="export">Export</Menu.Item>
</Menu.Content>
</Menu.Root>
)
}
Here's an example of how to create a mixed layout of menu items. In this layout, the top horizontal menu includes common menu items.
'use client'
import { Box, Group } from '@chakra-ui/react'
import { Button, Menu } from '@saas-ui/react'
import {
LuClipboard,
LuCopy,
LuFileSearch,
LuMessageSquare,
LuScissors,
LuShare,
} from 'react-icons/lu'
const horizontalMenuItems = [
{ label: 'Cut', value: 'cut', icon: <LuScissors /> },
{ label: 'Copy', value: 'copy', icon: <LuCopy /> },
{ label: 'Paste', value: 'paste', icon: <LuClipboard /> },
]
const verticalMenuItems = [
{ label: 'Look Up', value: 'look-up', icon: <LuFileSearch /> },
{ label: 'Translate', value: 'translate', icon: <LuMessageSquare /> },
{ label: 'Share', value: 'share', icon: <LuShare /> },
]
export const MenuWithMixedLayout = () => {
return (
<Menu.Root>
<Menu.Trigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</Menu.Trigger>
<Menu.Content>
<Group grow gap="0">
{horizontalMenuItems.map((item) => (
<Menu.Item
key={item.value}
value={item.value}
width="14"
gap="1"
flexDirection="column"
justifyContent="center"
>
{item.icon}
{item.label}
</Menu.Item>
))}
</Group>
{verticalMenuItems.map((item) => (
<Menu.Item key={item.value} value={item.value}>
<Box flex="1">{item.label}</Box>
{item.icon}
</Menu.Item>
))}
</Menu.Content>
</Menu.Root>
)
}
Prop | Default | Type |
---|---|---|
closeOnSelect | true | boolean Whether to close the menu when an option is selected |
composite | true | boolean Whether the menu is a composed with other composite widgets like a combobox or tabs |
lazyMount | false | boolean Whether to enable lazy mounting |
loopFocus | false | boolean Whether to loop the keyboard navigation. |
typeahead | true | boolean Whether the pressing printable characters should trigger typeahead navigation |
unmountOnExit | false | boolean Whether to unmount on exit. |
colorPalette | 'gray' | 'gray' | 'red' | 'orange' | 'yellow' | 'green' | 'teal' | 'blue' | 'cyan' | 'purple' | 'pink' | 'accent' The color palette of the component |
variant | 'subtle' | 'subtle' | 'solid' The variant of the component |
size | 'md' | 'sm' | 'md' The size of the component |
anchorPoint | Point The positioning point for the menu. Can be set by the context menu trigger or the button trigger. | |
aria-label | string The accessibility label for the menu | |
defaultOpen | boolean The initial open state of the menu when it is first rendered. Use when you do not need to control its open state. | |
highlightedValue | string The value of the highlighted menu item. | |
id | string The unique identifier of the machine. | |
ids | Partial<{
trigger: string
contextTrigger: string
content: string
groupLabel(id: string): string
group(id: string): string
positioner: string
arrow: string
}> The ids of the elements in the menu. Useful for composition. | |
immediate | boolean Whether to synchronize the present change immediately or defer it to the next frame | |
onEscapeKeyDown | (event: KeyboardEvent) => void Function called when the escape key is pressed | |
onExitComplete | () => void Function called when the animation ends in the closed state | |
onFocusOutside | (event: FocusOutsideEvent) => void Function called when the focus is moved outside the component | |
onHighlightChange | (details: HighlightChangeDetails) => void Function called when the highlighted menu item changes. | |
onInteractOutside | (event: InteractOutsideEvent) => void Function called when an interaction happens outside the component | |
onOpenChange | (details: OpenChangeDetails) => void Function called when the menu opens or closes | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => void Function called when the pointer is pressed down outside the component | |
onSelect | (details: SelectionDetails) => void Function called when a menu item is selected. | |
open | boolean Whether the menu is open | |
positioning | PositioningOptions The options used to dynamically position the menu | |
present | boolean Whether the node is present (controlled by the user) | |
as | React.ElementType The underlying element to render. | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
unstyled | boolean Whether to remove the component's style. |
Prop | Default | Type |
---|---|---|
value * | string The unique value of the menu item option. | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
closeOnSelect | boolean Whether the menu should be closed when the option is selected. | |
disabled | boolean Whether the menu item is disabled | |
valueText | string The textual value of the option. Used in typeahead navigation of the menu. If not provided, the text content of the menu item will be used. |