import { Button } from "@/components/ui/button"
import {
MenuContent,
MenuItem,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
const Demo = () => {
return (
<MenuRoot>
<MenuTrigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</MenuTrigger>
<MenuContent>
<MenuItem value="new-txt">New Text File</MenuItem>
<MenuItem value="new-file">New File...</MenuItem>
<MenuItem value="new-win">New Window</MenuItem>
<MenuItem value="open-file">Open File...</MenuItem>
<MenuItem value="export">Export</MenuItem>
</MenuContent>
</MenuRoot>
)
}
Setup
If you don't already have the snippet, run the following command to add the
menu
snippet
npx @chakra-ui/cli snippet add menu
The snippet includes a closed component composition for the Menu
component.
Usage
import {
MenuContent,
MenuItem,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
<MenuRoot>
<MenuTrigger />
<MenuContent>
<MenuItem value="..." />
</MenuContent>
</MenuRoot>
Examples
Command
Use the MenuItemCommand
component to display a command in the menu.
import { Button } from "@/components/ui/button"
import {
MenuContent,
MenuItem,
MenuItemCommand,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
const Demo = () => {
return (
<MenuRoot>
<MenuTrigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</MenuTrigger>
<MenuContent>
<MenuItem value="new-txt-a">
New Text File <MenuItemCommand>⌘E</MenuItemCommand>
</MenuItem>
<MenuItem value="new-file-a">
New File... <MenuItemCommand>⌘N</MenuItemCommand>
</MenuItem>
<MenuItem value="new-win-a">
New Window <MenuItemCommand>⌘⇧N</MenuItemCommand>
</MenuItem>
<MenuItem value="open-file-a">
Open File... <MenuItemCommand>⌘O</MenuItemCommand>
</MenuItem>
<MenuItem value="export-a">
Export <MenuItemCommand>⌘S</MenuItemCommand>
</MenuItem>
</MenuContent>
</MenuRoot>
)
}
Context menu
Use the MenuContextTrigger
component to create a context menu.
import { Center } from "@chakra-ui/react"
import {
MenuContent,
MenuContextTrigger,
MenuItem,
MenuRoot,
} from "@/components/ui/menu"
const Demo = () => {
return (
<MenuRoot>
<MenuContextTrigger w="full">
<Center
width="full"
height="40"
userSelect="none"
borderWidth="2px"
borderStyle="dashed"
rounded="lg"
padding="4"
>
Right click here
</Center>
</MenuContextTrigger>
<MenuContent>
<MenuItem value="new-txt">New Text File</MenuItem>
<MenuItem value="new-file">New File...</MenuItem>
<MenuItem value="new-win">New Window</MenuItem>
<MenuItem value="open-file">Open File...</MenuItem>
<MenuItem value="export">Export</MenuItem>
</MenuContent>
</MenuRoot>
)
}
Group
Use the MenuItemGroup
component to group related menu items.
import { Button } from "@/components/ui/button"
import {
MenuContent,
MenuItem,
MenuItemGroup,
MenuRoot,
MenuSeparator,
MenuTrigger,
} from "@/components/ui/menu"
const Demo = () => {
return (
<MenuRoot>
<MenuTrigger asChild>
<Button variant="outline">Edit</Button>
</MenuTrigger>
<MenuContent>
<MenuItemGroup title="Styles">
<MenuItem value="bold">Bold</MenuItem>
<MenuItem value="underline">Underline</MenuItem>
</MenuItemGroup>
<MenuSeparator />
<MenuItemGroup title="Align">
<MenuItem value="left">Left</MenuItem>
<MenuItem value="middle">Middle</MenuItem>
<MenuItem value="right">Right</MenuItem>
</MenuItemGroup>
</MenuContent>
</MenuRoot>
)
}
Danger Item
Here's an example of how to style a menu item that is used to delete an item.
import { Button } from "@/components/ui/button"
import {
MenuContent,
MenuItem,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
const Demo = () => {
return (
<MenuRoot>
<MenuTrigger asChild>
<Button variant="outline" size="sm">
Open Menu
</Button>
</MenuTrigger>
<MenuContent>
<MenuItem value="rename">Rename</MenuItem>
<MenuItem value="export">Export</MenuItem>
<MenuItem
value="delete"
color="fg.error"
_hover={{ bg: "bg.error", color: "fg.error" }}
>
Delete...
</MenuItem>
</MenuContent>
</MenuRoot>
)
}
Submenu
Here's an example of how to create a submenu.
import { Button } from "@/components/ui/button"
import {
MenuContent,
MenuItem,
MenuRoot,
MenuTrigger,
MenuTriggerItem,
} from "@/components/ui/menu"
const Demo = () => {
return (
<MenuRoot>
<MenuTrigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</MenuTrigger>
<MenuContent>
<MenuItem value="new-txt">New Text File</MenuItem>
<MenuItem value="new-file">New File...</MenuItem>
<MenuRoot positioning={{ placement: "right-start", gutter: 2 }}>
<MenuTriggerItem value="open-recent">Open Recent</MenuTriggerItem>
<MenuContent>
<MenuItem value="panda">Panda</MenuItem>
<MenuItem value="ark">Ark UI</MenuItem>
<MenuItem value="chakra">Chakra v3</MenuItem>
</MenuContent>
</MenuRoot>
<MenuItem value="open-file">Open File...</MenuItem>
<MenuItem value="export">Export</MenuItem>
</MenuContent>
</MenuRoot>
)
}
Links
Pass the asChild
prop to the MenuItem
component to render a link.
import { Button } from "@/components/ui/button"
import {
MenuContent,
MenuItem,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
const Demo = () => {
return (
<MenuRoot>
<MenuTrigger asChild>
<Button size="sm" variant="outline">
Select Anime
</Button>
</MenuTrigger>
<MenuContent>
<MenuItem asChild value="naruto">
<a
href="https://www.crunchyroll.com/naruto"
target="_blank"
rel="noreferrer"
>
Naruto
</a>
</MenuItem>
<MenuItem asChild value="one-piece">
<a
href="https://www.crunchyroll.com/one-piece"
target="_blank"
rel="noreferrer"
>
One Piece
</a>
</MenuItem>
<MenuItem asChild value="attack-on-titan">
<a
href="https://www.crunchyroll.com/attack-on-titan"
target="_blank"
rel="noreferrer"
>
Attack on Titan
</a>
</MenuItem>
</MenuContent>
</MenuRoot>
)
}
With Radio
Here's an example of how to create a menu with radio.
"use client"
import { Button } from "@/components/ui/button"
import {
MenuContent,
MenuRadioItem,
MenuRadioItemGroup,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
import { useState } from "react"
import { HiSortAscending } from "react-icons/hi"
const Demo = () => {
const [value, setValue] = useState("asc")
return (
<MenuRoot>
<MenuTrigger asChild>
<Button variant="outline" size="sm">
<HiSortAscending /> Sort
</Button>
</MenuTrigger>
<MenuContent minW="10rem">
<MenuRadioItemGroup
value={value}
onValueChange={(e) => setValue(e.value)}
>
<MenuRadioItem value="asc">Ascending</MenuRadioItem>
<MenuRadioItem value="desc">Descending</MenuRadioItem>
</MenuRadioItemGroup>
</MenuContent>
</MenuRoot>
)
}
Icon and Command
Compose the menu to include icons and commands.
import { Box } from "@chakra-ui/react"
import { Button } from "@/components/ui/button"
import {
MenuContent,
MenuItem,
MenuItemCommand,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
import { LuClipboardPaste, LuCopy, LuScissors } from "react-icons/lu"
const Demo = () => {
return (
<MenuRoot>
<MenuTrigger asChild>
<Button variant="outline">Edit</Button>
</MenuTrigger>
<MenuContent>
<MenuItem value="cut" valueText="cut">
<LuScissors />
<Box flex="1">Cut</Box>
<MenuItemCommand>⌘X</MenuItemCommand>
</MenuItem>
<MenuItem value="copy" valueText="copy">
<LuCopy />
<Box flex="1">Copy</Box>
<MenuItemCommand>⌘C</MenuItemCommand>
</MenuItem>
<MenuItem value="paste" valueText="paste">
<LuClipboardPaste />
<Box flex="1">Paste</Box>
<MenuItemCommand>⌘V</MenuItemCommand>
</MenuItem>
</MenuContent>
</MenuRoot>
)
}
Placement
Use the positioning.placement
prop to control the placement of the menu.
import { Button } from "@/components/ui/button"
import {
MenuContent,
MenuItem,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
const Demo = () => {
return (
<MenuRoot positioning={{ placement: "right-start" }}>
<MenuTrigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</MenuTrigger>
<MenuContent>
<MenuItem value="new-txt">New Text File</MenuItem>
<MenuItem value="new-file">New File...</MenuItem>
<MenuItem value="new-win">New Window</MenuItem>
<MenuItem value="open-file">Open File...</MenuItem>
<MenuItem value="export">Export</MenuItem>
</MenuContent>
</MenuRoot>
)
}
Mixed Layout
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.
import { Box, Group } from "@chakra-ui/react"
import { Button } from "@/components/ui/button"
import {
MenuContent,
MenuItem,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
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 /> },
]
const Demo = () => {
return (
<MenuRoot>
<MenuTrigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</MenuTrigger>
<MenuContent>
<Group grow gap="0">
{horizontalMenuItems.map((item) => (
<MenuItem
key={item.value}
value={item.value}
width="14"
gap="1"
flexDirection="column"
justifyContent="center"
>
{item.icon}
{item.label}
</MenuItem>
))}
</Group>
{verticalMenuItems.map((item) => (
<MenuItem key={item.value} value={item.value}>
<Box flex="1">{item.label}</Box>
{item.icon}
</MenuItem>
))}
</MenuContent>
</MenuRoot>
)
}
Props
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. |
Item
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. |