Overrides the parent menu's closeOnSelect prop.
Menu
An accessible dropdown menu for the common dropdown menu button design pattern. Menu uses roving tabIndex for focus management.
Import#
Chakra UI exports 8 components for rendering menus:
Menu: The wrapper component provides context, state, and focus management.MenuList: The wrapper for the menu items. Must be a direct child ofMenu.MenuButton: The trigger for the menu list. Must be a direct child ofMenu.MenuItem: The trigger that handles menu selection. Must be a direct child of aMenuList.MenuGroup: A wrapper to group related menu items.MenuDivider: A visual separator for menu items and groups.MenuOptionGroup: A wrapper for checkable menu items (radio and checkbox).MenuItemOption: The checkable menu item, to be used withMenuOptionGroup.
import {Menu,MenuButton,MenuList,MenuItem,MenuItemOption,MenuGroup,MenuOptionGroup,MenuDivider,} from '@chakra-ui/react'
Usage#
<Menu><MenuButton as={Button} rightIcon={<ChevronDownIcon />}>Actions</MenuButton><MenuList><MenuItem>Download</MenuItem><MenuItem>Create a Copy</MenuItem><MenuItem>Mark as Draft</MenuItem><MenuItem>Delete</MenuItem><MenuItem>Attend a Workshop</MenuItem></MenuList></Menu>
Accessing the internal state#
To access the internal state of the Menu, use a function as children
(commonly known as a render prop). You'll get access to the internal state
isOpen and method onClose.
<Menu>{({ isOpen }) => (<><MenuButton isActive={isOpen} as={Button} rightIcon={<ChevronDownIcon />}>{isOpen ? 'Close' : 'Open'}</MenuButton><MenuList><MenuItem>Download</MenuItem><MenuItem onClick={() => alert('Kagebunshin')}>Create a Copy</MenuItem></MenuList></>)}</Menu>
Customizing the button#
The default MenuButton can be styled using the usual styled-system props, but
it starts off plainly styled.
Using the as prop of the MenuButton, you can render a custom component
instead of the default MenuButton. For instance, you can use Chakra's Button
component, or your own custom component.
If you decide to pass your own component to
MenuButton, it needs to accept arefso that theMenuListcan be positioned correctly. You can use Chakra'sforwardRefto supply therefalong with being able to use Chakra props. Without aref, theMenuListwill render in an undefined position.
See the documentation on setting up the forwardRef with your custom component.
Letter Navigation#
When focus is on the MenuButton or within the MenuList and you type a letter
key, a search begins. Focus will move to the first MenuItem that starts with
the letter you typed.
Open the menu, try and type any letter, (say "S") to see the focus movement.
<Menu><MenuButtonpx={4}py={2}transition='all 0.2s'borderRadius='md'borderWidth='1px'_hover={{ bg: 'gray.400' }}_expanded={{ bg: 'blue.400' }}_focus={{ boxShadow: 'outline' }}>File <ChevronDownIcon /></MenuButton><MenuList><MenuItem>New File</MenuItem><MenuItem>New Window</MenuItem><MenuDivider /><MenuItem>Open...</MenuItem><MenuItem>Save File</MenuItem></MenuList></Menu>
Just another example#
<Menu><MenuButton as={Button} rightIcon={<ChevronDownIcon />}>Your Cats</MenuButton><MenuList><MenuItem minH='48px'><ImageboxSize='2rem'borderRadius='full'src='https://placekitten.com/100/100'alt='Fluffybuns the destroyer'mr='12px'/><span>Fluffybuns the Destroyer</span></MenuItem><MenuItem minH='40px'><ImageboxSize='2rem'borderRadius='full'src='https://placekitten.com/120/120'alt='Simon the pensive'mr='12px'/><span>Simon the pensive</span></MenuItem></MenuList></Menu>
Adding icons and commands#
You can add icon to each MenuItem by passing the icon prop. To add a
commands (or hotkeys) to menu items, you can use the command prop.
<Menu><MenuButtonas={IconButton}aria-label='Options'icon={<HamburgerIcon />}variant='outline'/><MenuList><MenuItem icon={<AddIcon />} command='⌘T'>New Tab</MenuItem><MenuItem icon={<ExternalLinkIcon />} command='⌘N'>New Window</MenuItem><MenuItem icon={<RepeatIcon />} command='⌘⇧N'>Open Closed Tab</MenuItem><MenuItem icon={<EditIcon />} command='⌘O'>Open File...</MenuItem></MenuList></Menu>
Lazily mounting MenuItem#
By default, the Menu component renders all children of MenuList to the DOM,
meaning that invisible menu items are still rendered but are hidden by styles.
If you want to defer rendering of each children of MenuList until that menu is
open, you can use the isLazy prop. This is useful if your Menu needs to be
extra performant, or make network calls on mount that should only happen when
the component is displayed.
<Menu isLazy><MenuButton>Open menu</MenuButton><MenuList>{/* MenuItems are not rendered unless Menu is open */}<MenuItem>New Window</MenuItem><MenuItem>Open Closed Tab</MenuItem><MenuItem>Open File</MenuItem></MenuList></Menu>
Rendering menu in a portal#
To render menus in a portal, import the Portal component and wrap the
MenuList within the Portal.
<Menu><MenuButton>Open menu</MenuButton><Portal><MenuList><MenuItem>Menu 1</MenuItem><MenuItem>New Window</MenuItem><MenuItem>Open Closed Tab</MenuItem><MenuItem>Open File</MenuItem></MenuList></Portal></Menu>
MenuGroup#
To group related MenuItems, use the MenuGroup component and pass it a
title for the group name.
<Menu><MenuButton as={Button} colorScheme='pink'>Profile</MenuButton><MenuList><MenuGroup title='Profile'><MenuItem>My Account</MenuItem><MenuItem>Payments </MenuItem></MenuGroup><MenuDivider /><MenuGroup title='Help'><MenuItem>Docs</MenuItem><MenuItem>FAQ</MenuItem></MenuGroup></MenuList></Menu>
MenuItem as a link#
To render a MenuItem as a link, use the attributes as and href.
<Menu><MenuButton>Open menu</MenuButton><MenuList><MenuItem as='a' href='#'>Link 1</MenuItem><MenuItem as='a' href='#'>Link 2</MenuItem></MenuList></Menu>
Menu option groups#
You can compose a menu for table headers to help with sorting and filtering
options. Use the MenuOptionGroup and MenuItemOption components.
<Menu closeOnSelect={false}><MenuButton as={Button} colorScheme='blue'>MenuItem</MenuButton><MenuList minWidth='240px'><MenuOptionGroup defaultValue='asc' title='Order' type='radio'><MenuItemOption value='asc'>Ascending</MenuItemOption><MenuItemOption value='desc'>Descending</MenuItemOption></MenuOptionGroup><MenuDivider /><MenuOptionGroup title='Country' type='checkbox'><MenuItemOption value='email'>Email</MenuItemOption><MenuItemOption value='phone'>Phone</MenuItemOption><MenuItemOption value='country'>Country</MenuItemOption></MenuOptionGroup></MenuList></Menu>
Accessibility#
Keyboard Interaction#
| Key | Action |
|---|---|
Enter or Space | When MenuButton receives focus, opens the menu and places focus on the first menu item. |
ArrowDown | When MenuButton receives focus, opens the menu and moves focus to the first menu item. |
ArrowUp | When MenuButton receives focus, opens the menu and moves focus to the last menu item. |
Escape | When the menu is open, closes the menu and sets focus to the MenuButton. |
Tab | no effect |
Home | When the menu is open, moves focus to the first item. |
End | When the menu is open, moves focus to the last item. |
A-Z or a-z | When the menu is open, moves focus to the next menu item with a label that starts with the typed character if such an menu item exists. |
ARIA roles#
For MenuButton:
roleis set tobutton.aria-haspopupis set tomenu.- When the menu is displayed,
aria-expandedis set totrue. aria-controlsis set to theidof theMenuList.
For MenuList:
roleis set tomenu.aria-orientationis set tovertical.
For MenuItem:
roleis set tomenuitem.- Gets one of these roles
menuitem/menuitemradio/menuitemcheckbox.
Props#
Menu Props#
MenuButton Props#
MenuButton composes Box so you can pass all
Box props to change its style.
MenuList Props#
MenuList composes Box so you can pass all Box
props to change its style.
MenuItem Props#
closeOnSelect
closeOnSelectbooleancommand
commandRight-aligned label text content, useful for displaying hotkeys.
stringcommandSpacing
commandSpacingThe spacing between the command and menu item's label.
ResponsiveValue<string | number | (string & {})>icon
iconThe icon to render before the menu item's label.
ReactElement<any, string | JSXElementConstructor<any>>iconSpacing
iconSpacingThe spacing between the icon and menu item's label.
ResponsiveValue<string | number | (string & {})>isDisabled
isDisabledIf true, the menuitem will be disabled
booleanisFocusable
isFocusableIf true and the menuitem is disabled, it'll
remain keyboard-focusable
booleanMenuGroup Props#
MenuGroup composes Box so you can pass all
Box props to change its style.
MenuOptionGroup Props#
defaultValue
defaultValuestring | string[]onChange
onChange(value: string | string[]) => voidtype
type"radio" | "checkbox"value
valuestring | string[]MenuItemOption Props#
MenuItemOption composes Box so you can pass all
box props in addition to these:
closeOnSelect
closeOnSelectOverrides the parent menu's closeOnSelect prop.
booleancommand
commandRight-aligned label text content, useful for displaying hotkeys.
stringcommandSpacing
commandSpacingThe spacing between the command and menu item's label.
ResponsiveValue<string | number | (string & {})>icon
iconReactElement<any, string | JSXElementConstructor<any>>iconSpacing
iconSpacingThe spacing between the icon and menu item's label.
ResponsiveValue<string | number | (string & {})>isChecked
isCheckedbooleanisDisabled
isDisabledIf true, the menuitem will be disabled
booleanisFocusable
isFocusableIf true and the menuitem is disabled, it'll
remain keyboard-focusable
booleantype
type"radio" | "checkbox"value
valuestringThe Menu component is a multipart component. The styling needs to be applied
to each part specifically.
To learn more about styling multipart components, visit the Component Style page.
Anatomy#
- A:
button - B:
list - C:
item - D:
groupTitle - E:
command - F:
divider
Theming properties#
The properties that affect the theming of the Menu component are:
variant: The visual variant of the component. There is no default applied.size: The size of the component. There is no default applied.
Theming utilities#
createMultiStyleConfigHelpers: a function that returns a set of utilities for creating style configs for a multipart component (definePartsStyleanddefineMultiStyleConfig).definePartsStyle: a function used to create multipart style objects.defineMultiStyleConfig: a function used to define the style configuration for a multipart component.
import { menuAnatomy } from '@chakra-ui/anatomy'import { createMultiStyleConfigHelpers, defineStyle } from '@chakra-ui/react'const { definePartsStyle, defineMultiStyleConfig } =createMultiStyleConfigHelpers(menuAnatomy.keys)
Customizing the default theme#
import { menuAnatomy } from '@chakra-ui/anatomy'import { createMultiStyleConfigHelpers, defineStyle } from '@chakra-ui/react'const { definePartsStyle, defineMultiStyleConfig } =createMultiStyleConfigHelpers(menuAnatomy.keys)// define the base component stylesconst baseStyle = definePartsStyle({// define the part you're going to stylebutton: {// this will style the MenuButton componentfontWeight: 'medium',bg: 'teal.500',color: 'gray.200',_hover: {bg: 'teal.600',color: 'white',},},list: {// this will style the MenuList componentpy: '4',borderRadius: 'xl',border: 'none',bg: 'teal.500',},item: {// this will style the MenuItem and MenuItemOption componentscolor: 'gray.200',_hover: {bg: 'teal.600',},_focus: {bg: 'teal.600',},},groupTitle: {// this will style the text defined by the title prop// in the MenuGroup and MenuOptionGroup componentstextTransform: 'uppercase',color: 'white',textAlign: 'center',letterSpacing: 'wider',opacity: '0.7',},command: {// this will style the text defined by the command// prop in the MenuItem and MenuItemOption componentsopacity: '0.8',fontFamily: 'mono',fontSize: 'sm',letterSpacing: 'tighter',pl: '4',},divider: {// this will style the MenuDivider componentmy: '4',borderColor: 'white',borderBottom: '2px dotted',},})// export the base styles in the component themeexport const menuTheme = defineMultiStyleConfig({ baseStyle })
After customizing the input theme, we can import it into our theme file and add
it in the components property:
import { extendTheme } from '@chakra-ui/react'import { menuTheme } from './components/Menu'const theme = extendTheme({components: {Menu: menuTheme,},})export default theme
This is a crucial step to make sure that any changes we make to the menu theme are applied.
Adding a custom size#
Let's assume we want to include an extra large menu size. Here's how we can do that:
import { menuAnatomy } from '@chakra-ui/anatomy'import { createMultiStyleConfigHelpers, defineStyle } from '@chakra-ui/react'const { definePartsStyle, defineMultiStyleConfig } =createMultiStyleConfigHelpers(menuAnatomy.keys)// define custom stylesconst lg = defineStyle({fontSize: 'md',my: '1',})const xl = defineStyle({fontSize: 'lg',px: '4',py: '2',})// define custom sizesconst sizes = {// apply custom styles to partsxl: definePartsStyle({ button: xl, item: xl, groupTitle: lg, command: xl }),}// export the sizes in the component themeexport const menuTheme = defineMultiStyleConfig({ sizes })// now we can use the new `xl` size<Menu size="xl" ... />
Every time you add anything new to the theme, you need to run the CLI command to get proper autocomplete in your IDE. You can learn more about the CLI tool here.
Adding a custom variant#
Let's assume we want to include some custom variants to create a pill-shaped menu bar. Here's how we can do that:
import { menuAnatomy } from '@chakra-ui/anatomy'import { createMultiStyleConfigHelpers, defineStyle } from '@chakra-ui/react'const { definePartsStyle, defineMultiStyleConfig } =createMultiStyleConfigHelpers(menuAnatomy.keys)// define custom variantsconst variants = {roundLeft: {button: {borderLeftRadius: 'full',pl: '6',},},roundRight: {button: {borderRightRadius: 'full',pr: '6',},},}// export the custom variants in the component themeexport const menuTheme = defineMultiStyleConfig({ variants })// now we can use the new `roundLeft` and `roundRight` variants<Menu variant="roundLeft" ... /><Menu variant="roundRight" ... />
Changing the default properties#
Let's assume we want to change the default size and variant of every menu in our app. Here's how we can do that:
import { menuAnatomy } from '@chakra-ui/anatomy'import { createMultiStyleConfigHelpers, defineStyle } from '@chakra-ui/react'const { definePartsStyle, defineMultiStyleConfig } =createMultiStyleConfigHelpers(menuAnatomy.keys)// define which sizes and variants are applied by defaultconst defaultProps = {// in this example, we will only set a default sizesize: 'xl',}// export the default properties in the component themeexport const menuTheme = defineMultiStyleConfig({ defaultProps })
Showcase#
import { ChakraProvider, Menu, MenuButton, MenuList, MenuItem, MenuItemOption, MenuGroup, MenuOptionGroup, MenuDivider, Box, Center, } from '@chakra-ui/react'; import theme from './theme'; import { ColorModeSwitcher } from './ColorModeSwitcher'; export default function App() { return ( <ChakraProvider theme={theme}> <Box position="relative" h="100vh" p={12}> <Center> <Menu variant="roundLeft"> <MenuButton>File</MenuButton> <MenuList> <MenuItem command="Ctrl + N">New File</MenuItem> <MenuItem command="Ctrl + O">Open File</MenuItem> <MenuDivider /> <MenuGroup title="Save"> <MenuItem command="Ctrl + S">Save</MenuItem> <MenuItem command="Ctrl + Shift + S">Save As...</MenuItem> <MenuItem command="Ctrl + Alt + S">Save All</MenuItem> </MenuGroup> <MenuDivider /> <MenuItem>Exit</MenuItem> </MenuList> </Menu> <Menu> <MenuButton>Edit</MenuButton> <MenuList> <MenuItem command="Ctrl + Z">Undo</MenuItem> <MenuItem command="Ctrl + Y">Redo</MenuItem> <MenuDivider /> <MenuGroup> <MenuItem command="Ctrl + X">Cut</MenuItem> <MenuItem command="Ctrl + C">Copy</MenuItem> <MenuItem command="Ctrl + V">Paste</MenuItem> </MenuGroup> </MenuList> </Menu> <Menu variant="roundRight"> <MenuButton>View</MenuButton> <MenuList> <MenuItem command="Ctrl + F">Full Screen Mode</MenuItem> <MenuItem command="Ctrl + R">Reading Mode</MenuItem> <MenuDivider /> <MenuGroup title="Zoom"> <MenuItem command="Ctrl + 1">Actual Size</MenuItem> <MenuItem command="Ctrl + 2">Fit Width</MenuItem> <MenuItem command="Ctrl + 3">Height</MenuItem> </MenuGroup> <MenuDivider /> <MenuOptionGroup title="Display Size" type="radio" defaultValue={'standard'} > <MenuItemOption value="small" closeOnSelect={false}> Small </MenuItemOption> <MenuItemOption value="standard" closeOnSelect={false}> Standard </MenuItemOption> <MenuItemOption value="large" closeOnSelect={false}> Large </MenuItemOption> </MenuOptionGroup> </MenuList> </Menu> </Center> <ColorModeSwitcher aria-label="toggle theme" position="absolute" bottom={4} left={4} /> </Box> </ChakraProvider> ); }