import { Button } from "@chakra-ui/react"
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 "@chakra-ui/react"
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 "@chakra-ui/react"
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 "@chakra-ui/react"
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 "@chakra-ui/react"
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 "@chakra-ui/react"
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>
)
}
When using custom router links, you need to set the navigate prop on the
MenuRoot component.
"use client"
import { Menu } from "@/components/ui/menu"
import { useNavigate } from "react-router-dom"
const Demo = () => {
const navigate = useNavigate()
return (
<MenuRoot navigate={({ value, node }) => navigate(`/${value}`)}>
{/* ... */}
</MenuRoot>
)
}
Radio Items
Here's an example of how to create a menu with radio items.
"use client"
import { Button } from "@chakra-ui/react"
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>
)
}
Checkbox Items
Here's an example of how to create a menu with checkbox items.
"use client"
import { Button, useCheckboxGroup } from "@chakra-ui/react"
import {
MenuCheckboxItem,
MenuContent,
MenuItemGroup,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
import { HiCog } from "react-icons/hi"
const Demo = () => {
const group = useCheckboxGroup({ defaultValue: ["bar"] })
return (
<MenuRoot>
<MenuTrigger asChild>
<Button variant="outline" size="sm">
<HiCog /> Features
</Button>
</MenuTrigger>
<MenuContent>
<MenuItemGroup title="Features">
{items.map(({ title, value }) => (
<MenuCheckboxItem
key={value}
value={value}
checked={group.isChecked(value)}
onCheckedChange={() => group.toggleValue(value)}
>
{title}
</MenuCheckboxItem>
))}
</MenuItemGroup>
</MenuContent>
</MenuRoot>
)
}
const items = [
{ title: "Autosave", value: "autosave" },
{ title: "Detect Language", value: "detect-language" },
{ title: "Spellcheck", value: "spellcheck" },
]
Icon and Command
Compose the menu to include icons and commands.
import { Box, Button } from "@chakra-ui/react"
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 "@chakra-ui/react"
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, Button, Group } from "@chakra-ui/react"
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>
)
}
Hide When Detached
When the menu is rendered in an scrolling container, set the
positioning.hideWhenDetached to true to hide the menu when the trigger is
scrolled out of view.
Item0
Item1
Item2
Item3
Item4
Item5
import { Box, Center, Flex, Text } from "@chakra-ui/react"
import {
MenuContent,
MenuItem,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
const Demo = () => {
return (
<Center minH="sm">
<Flex
w="300px"
h="full"
overflowX="auto"
gapX="6"
p="4"
borderWidth="1px"
bg="bg.subtle"
>
{[...Array(6).keys()].map((x) => (
<Box layerStyle="fill.surface" p="4" borderRadius="md" key={x}>
<Text>Item{x}</Text>
</Box>
))}
<Box>
<MenuRoot positioning={{ hideWhenDetached: true }}>
<MenuTrigger asChild>
<Box as="button" bg="green.100" p="4" borderRadius="md">
Menu
</Box>
</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>
</Box>
</Flex>
</Center>
)
}
Within Dialog
Here's an example of how to use the menu within a Dialog or Drawer
component.
Due to the focus trap within the dialog, it's important to change the portal target from the document's body to the dialog's content.
"use client"
import { Button } from "@chakra-ui/react"
import {
DialogBody,
DialogContent,
DialogHeader,
DialogRoot,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import {
MenuContent,
MenuItem,
MenuRoot,
MenuTrigger,
} from "@/components/ui/menu"
import { useRef } from "react"
import Lorem from "react-lorem-ipsum"
const Demo = () => {
const contentRef = useRef<HTMLDivElement>(null)
return (
<DialogRoot>
<DialogTrigger asChild>
<Button variant="outline" size="sm">
Open
</Button>
</DialogTrigger>
<DialogContent ref={contentRef}>
<DialogHeader>
<DialogTitle>Welcome to the menu</DialogTitle>
</DialogHeader>
<DialogBody spaceY="4">
<MenuRoot>
<MenuTrigger asChild>
<Button variant="outline" size="sm">
Menu
</Button>
</MenuTrigger>
<MenuContent portalRef={contentRef}>
<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>
<Lorem p={1} />
</DialogBody>
</DialogContent>
</DialogRoot>
)
}
Props
Root
| Prop | Default | Type |
|---|---|---|
closeOnSelect | true | booleanWhether to close the menu when an option is selected |
composite | true | booleanWhether the menu is a composed with other composite widgets like a combobox or tabs |
lazyMount | false | booleanWhether to enable lazy mounting |
loopFocus | false | booleanWhether to loop the keyboard navigation. |
typeahead | true | booleanWhether the pressing printable characters should trigger typeahead navigation |
unmountOnExit | false | booleanWhether 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 | PointThe positioning point for the menu. Can be set by the context menu trigger or the button trigger. | |
aria-label | stringThe accessibility label for the menu | |
defaultOpen | booleanThe initial open state of the menu when it is first rendered. Use when you do not need to control its open state. | |
highlightedValue | stringThe value of the highlighted menu item. | |
id | stringThe 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 | booleanWhether to synchronize the present change immediately or defer it to the next frame | |
navigate | (details: NavigateDetails) => voidFunction to navigate to the selected item if it's an anchor element | |
onEscapeKeyDown | (event: KeyboardEvent) => voidFunction called when the escape key is pressed | |
onExitComplete | () => voidFunction called when the animation ends in the closed state | |
onFocusOutside | (event: FocusOutsideEvent) => voidFunction called when the focus is moved outside the component | |
onHighlightChange | (details: HighlightChangeDetails) => voidFunction called when the highlighted menu item changes. | |
onInteractOutside | (event: InteractOutsideEvent) => voidFunction called when an interaction happens outside the component | |
onOpenChange | (details: OpenChangeDetails) => voidFunction called when the menu opens or closes | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => voidFunction called when the pointer is pressed down outside the component | |
onSelect | (details: SelectionDetails) => voidFunction called when a menu item is selected. | |
open | booleanWhether the menu is open | |
positioning | PositioningOptionsThe options used to dynamically position the menu | |
present | booleanWhether the node is present (controlled by the user) | |
as | React.ElementTypeThe underlying element to render. | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
unstyled | booleanWhether to remove the component's style. |
Item
| Prop | Default | Type |
|---|---|---|
value * | stringThe unique value of the menu item option. | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
closeOnSelect | booleanWhether the menu should be closed when the option is selected. | |
disabled | booleanWhether the menu item is disabled | |
valueText | stringThe 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. |