Menu

A list of options to help users navigate, or perform actions.

Neutral selected states

When the platform-dst-tokens-finesse feature flag is enabled, this component uses the new neutral treatment for selected states.

Default

The menu is a collection of composable menu components to help with wayfinding.

import React from 'react'; import ButtonItem from '@atlaskit/menu/button-item'; import MenuGroup from '@atlaskit/menu/menu-group'; import Section from '@atlaskit/menu/section'; import ImgIcon from '../common/img-icon'; import MenuGroupContainer from '../common/menu-group-container'; import battery from '../icons/battery.png'; import cloud from '../icons/cloud.png'; import Drill from '../icons/drill.png'; import koala from '../icons/koala.png'; import ui from '../icons/ui.png'; import wallet from '../icons/wallet.png'; import Yeti from '../icons/yeti.png'; export default (): React.JSX.Element => ( <MenuGroupContainer> <MenuGroup> <Section title="Starred"> <ButtonItem iconBefore={<ImgIcon src={Yeti} alt={'Yeti'} />} description="Next-gen software project" > Navigation System </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={Drill} alt={'Drill'} />} description="Next-gen service desk" > Analytics Platform </ButtonItem> </Section> <Section title="Recent"> <ButtonItem iconBefore={<ImgIcon src={battery} alt={'Battery'} />} description="Next-gen software project" > Fabric Editor </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={cloud} alt={'Cloud'} />} description="Classic business project" > Content Services </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={wallet} alt={'Wallet'} />} description="Next-gen software project" > Trinity Mobile </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={koala} alt={'Koala'} />} description="Classic service desk" > Customer Feedback </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={ui} alt={'UI icon'} />} description="Classic software project" > Design System </ButtonItem> </Section> <Section hasSeparator> <ButtonItem>View all projects</ButtonItem> <ButtonItem>Create project</ButtonItem> </Section> </MenuGroup> </MenuGroupContainer> );

Use menu groups, sections and heading items to structure the menu.

Projects
import React from 'react'; import ButtonItem from '@atlaskit/menu/button-item'; import HeadingItem from '@atlaskit/menu/heading-item'; import MenuGroup from '@atlaskit/menu/menu-group'; import Section from '@atlaskit/menu/section'; import ImgIcon from '../common/img-icon'; import MenuGroupContainer from '../common/menu-group-container'; import battery from '../icons/battery.png'; import cloud from '../icons/cloud.png'; import Drill from '../icons/drill.png'; import koala from '../icons/koala.png'; import ui from '../icons/ui.png'; import wallet from '../icons/wallet.png'; import Yeti from '../icons/yeti.png'; export default (): React.JSX.Element => ( <MenuGroupContainer> <MenuGroup> <Section title="Starred"> <ButtonItem iconBefore={<ImgIcon src={Yeti} alt={'Yeti'} />} description="Next-gen software project" > Navigation System </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={Drill} alt={'Drill'} />} description="Next-gen service desk" > Analytics Platform </ButtonItem> </Section> <Section title="Recent"> <ButtonItem iconBefore={<ImgIcon src={battery} alt={'Battery'} />} description="Next-gen software project" > Fabric Editor </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={cloud} alt={'Cloud'} />} description="Classic business project" > Content Services </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={wallet} alt={'Wallet'} />} description="Next-gen software project" > Trinity Mobile </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={koala} alt={'Koala'} />} description="Classic service desk" > Customer Feedback </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={ui} alt={'UI icon'} />} description="Classic software project" > Design System </ButtonItem> </Section> <Section hasSeparator> <HeadingItem>Projects</HeadingItem> <ButtonItem>View all projects</ButtonItem> <ButtonItem>Create project</ButtonItem> </Section> </MenuGroup> </MenuGroupContainer> );

Button item

The button item component renders a menu item wrapped in a button tag <button>. Use this component when you have an action that does something other than navigating to a new page or context.

import { cssMap, jsx } from '@compiled/react'; import ButtonItem from '@atlaskit/menu/button-item'; import { token } from '@atlaskit/tokens'; import ImgIcon from '../common/img-icon'; import Yeti from '../icons/yeti.png'; // Mimics overrides in side-navigation const styles = cssMap({ root: { paddingBlockStart: token('space.100'), paddingInlineEnd: token('space.300'), paddingBlockEnd: token('space.100'), paddingInlineStart: token('space.300'), borderRadius: token('radius.small'), backgroundColor: '#FAFBFC', color: '#42526E', '&:hover': { backgroundColor: '#EBECF0', textDecoration: 'none', color: '#42526E', }, '&:active': { color: '#0052CC', backgroundColor: '#DEEBFF', boxShadow: 'none', }, '[data-item-elem-before]': { display: 'flex', height: 8 * 1.25, width: 8 * 1.25, alignItems: 'center', justifyContent: 'center', marginInlineEnd: token('space.200'), }, }, disabled: { color: token('color.text.disabled'), backgroundColor: '#FAFBFC', '&:hover, &:active': { backgroundColor: '#FAFBFC', color: token('color.text.disabled'), }, }, }); const _default: () => JSX.Element = () => ( <div data-testid="button-items"> <ButtonItem isSelected>Activate</ButtonItem> <ButtonItem isDisabled>Activate</ButtonItem> <ButtonItem>Activate</ButtonItem> <ButtonItem description="Next-gen software project">Activate</ButtonItem> <ButtonItem description="Legacy software project" isDisabled> Activate </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={Yeti} alt="" />} description="Next-gen software project"> Activate </ButtonItem> <ButtonItem css={styles.root} description="Style overrides"> Activate </ButtonItem> <ButtonItem isDisabled css={[styles.root, styles.disabled]} description="Style overrides"> Activate </ButtonItem> <ButtonItem css={styles.root} description="Style overrides"> Activate </ButtonItem> </div> ); export default _default;

The link item component renders a menu item wrapped in an anchor tag <a>. This is the most common type of menu item, as most menu items are used to send people to another location.

For menu items that do something else, use the button item component instead.

If you need to use a specific router component for route transitions, you'll want to compose them together using the custom item component.

Custom item

Use custom item when you want to create a item using a your own component that inherits the look and feel of a menu item. For example, to use your own router link component. Your custom component will be given all overflow props passed to the custom item component.

import { cssMap, jsx } from '@compiled/react'; import CustomItem from '@atlaskit/menu/custom-item'; // Legacy example: this prop type is deprecated with @atlaskit/side-navigation. // Use @atlaskit/navigation-system for new side navigation. import { type CustomItemComponentProps } from '@atlaskit/menu/types'; import { Box } from '@atlaskit/primitives/compiled/box'; import Slack from '../icons/slack'; type CustomComponentWithHrefProps = CustomItemComponentProps & { href: string; }; const CustomComponent = ({ children, href, ...props }: CustomComponentWithHrefProps) => { return ( <a href={href} {...props}> {children} </a> ); }; const styles = cssMap({ root: { position: 'relative', overflow: 'hidden', userSelect: 'none', }, interactive: { '&::before': { content: '""', position: 'absolute', insetInlineStart: 0, insetBlockStart: 0, insetBlockEnd: 0, width: 3, transform: 'translateX(-1px)', transition: 'transform 70ms ease-in-out', backgroundColor: '#4C9AFF', }, '&:hover::before': { transform: 'translateX(0)', }, }, }); const _default: () => JSX.Element = () => ( /** * It is not normally acceptable to add click handlers to non-interactive elements * as this is an accessibility anti-pattern. However, because this instance is * for performance reasons (to avoid multiple click handlers) and not creating an * inaccessible custom element, we can add role="presentation" so that there is * no negative impacts to assistive technologies. */ <Box onClick={(e: React.MouseEvent) => e.preventDefault()} role="presentation"> <CustomItem href="/navigation-system" component={CustomComponent} css={[styles.root, styles.interactive]} > CustomItem </CustomItem> <CustomItem href="/navigation-system-1" isSelected component={CustomComponent} css={[styles.root, styles.interactive]} > isSelected CustomItem </CustomItem> <CustomItem href="/navigation-system-2" isDisabled component={CustomComponent} css={styles.root} > isDisabled CustomItem </CustomItem> <CustomItem href="/navigation-system-3" component={CustomComponent} iconBefore={<Slack />} css={[styles.root, styles.interactive]} > iconBefore CustomItem </CustomItem> <CustomItem href="/navigation-system-4" component={CustomComponent} iconBefore={<Slack />} description="Next-gen software project" css={[styles.root, styles.interactive]} > iconBefore and description CustomItem </CustomItem> </Box> ); export default _default;

Section and heading item

When there are a large number of items in a menu, allowing users who navigate with a screen reader to skip over sections can greatly improve the user experience. This behavior is done by default with this component by setting a group role and label.

import React from 'react'; import ButtonItem from '@atlaskit/menu/button-item'; import MenuGroup from '@atlaskit/menu/menu-group'; import Section from '@atlaskit/menu/section'; import MenuGroupContainer from '../common/menu-group-container'; export default (): React.JSX.Element => ( <MenuGroupContainer> <MenuGroup> <Section title="Actions"> <ButtonItem>Create article</ButtonItem> </Section> <Section> <ButtonItem>Create article</ButtonItem> </Section> </MenuGroup> </MenuGroupContainer> );

Custom heading item

It may be necessary to manually set the HeadingItem; in these cases the below code provides an example of how to maintain accessibility.

import React from 'react'; import ButtonItem from '@atlaskit/menu/button-item'; import HeadingItem from '@atlaskit/menu/heading-item'; import MenuGroup from '@atlaskit/menu/menu-group'; import Section from '@atlaskit/menu/section'; import MenuGroupContainer from '../common/menu-group-container'; export default (): React.JSX.Element => ( <MenuGroupContainer> <MenuGroup> <Section aria-labelledby="actions"> <HeadingItem id="actions" aria-hidden> Actions </HeadingItem> <ButtonItem>Create article</ButtonItem> </Section> </MenuGroup> </MenuGroupContainer> );

Heading item level

Using headingLevel prop to change the level of the heading. The default heading level is h2. Make sure that headings are in the correct order relative to the pages the menu is on, and don’t skip levels.

Heading level 2 (default)
Heading level 3
Heading level 4
Heading level 5
Heading level 6
import React from 'react'; import HeadingItem from '@atlaskit/menu/heading-item'; import MenuGroup from '@atlaskit/menu/menu-group'; import Section from '@atlaskit/menu/section'; import MenuGroupContainer from '../common/menu-group-container'; export default (): React.JSX.Element => ( <MenuGroupContainer> <MenuGroup> <Section> <HeadingItem>Heading level 2 (default)</HeadingItem> </Section> <Section> <HeadingItem headingLevel={3}>Heading level 3</HeadingItem> </Section> <Section> <HeadingItem headingLevel={4}>Heading level 4</HeadingItem> </Section> <Section> <HeadingItem headingLevel={5}>Heading level 5</HeadingItem> </Section> <Section> <HeadingItem headingLevel={6}>Heading level 6</HeadingItem> </Section> </MenuGroup> </MenuGroupContainer> );

Density

The menu group can be configured to accept different spacing values. Applying a compact spacing value will trim the gutters and whitespace, for higher density content.

import React from 'react'; import ButtonItem from '@atlaskit/menu/button-item'; import MenuGroup from '@atlaskit/menu/menu-group'; import Section from '@atlaskit/menu/section'; import ImgIcon from '../common/img-icon'; import MenuGroupContainer from '../common/menu-group-container'; import battery from '../icons/battery.png'; import cloud from '../icons/cloud.png'; import Drill from '../icons/drill.png'; import koala from '../icons/koala.png'; import ui from '../icons/ui.png'; import wallet from '../icons/wallet.png'; import Yeti from '../icons/yeti.png'; export default (): React.JSX.Element => ( <MenuGroupContainer> <MenuGroup spacing="compact"> <Section title="Starred"> <ButtonItem iconBefore={<ImgIcon src={Yeti} alt={'Yeti'} />} description="Next-gen software project" > Navigation System </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={Drill} alt={'Drill'} />} description="Next-gen service desk" > Analytics Platform </ButtonItem> </Section> <Section title="Recent"> <ButtonItem iconBefore={<ImgIcon src={battery} alt={'Battery'} />} description="Next-gen software project" > Fabric Editor </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={cloud} alt={'Cloud'} />} description="Classic business project" > Content Services </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={wallet} alt={'Wallet'} />} description="Next-gen software project" > Trinity Mobile </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={koala} alt={'Koala'} />} description="Classic service desk" > Customer Feedback </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={ui} alt={'UI icon'} />} description="Classic software project" > Design System </ButtonItem> </Section> <Section hasSeparator> <ButtonItem>View all projects</ButtonItem> <ButtonItem>Create project</ButtonItem> </Section> </MenuGroup> </MenuGroupContainer> );

Scrolling

Scrollable menu

Menus can be scrollable to fit a fixed height or space.

import React from 'react'; import ButtonItem from '@atlaskit/menu/button-item'; import MenuGroup from '@atlaskit/menu/menu-group'; import Section from '@atlaskit/menu/section'; import ImgIcon from '../common/img-icon'; import MenuGroupContainer from '../common/menu-group-container'; import battery from '../icons/battery.png'; import cloud from '../icons/cloud.png'; import Drill from '../icons/drill.png'; import koala from '../icons/koala.png'; import ui from '../icons/ui.png'; import wallet from '../icons/wallet.png'; import Yeti from '../icons/yeti.png'; export default (): React.JSX.Element => { return ( <MenuGroupContainer> <MenuGroup maxHeight={300}> <Section title="starred"> <ButtonItem iconBefore={<ImgIcon src={Yeti} alt={'Yeti'} />} description="Next-gen software project" > Navigation System </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={Drill} alt={'Drill'} />} description="Next-gen service desk" > Analytics Platform </ButtonItem> </Section> <Section title="Recent"> <ButtonItem iconBefore={<ImgIcon src={battery} alt={'Battery'} />} description="Next-gen software project" > Fabric Editor </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={cloud} alt={'Cloud'} />} description="Classic business project" > Content Services </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={wallet} alt={'Wallet'} />} description="Next-gen software project" > Trinity Mobile </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={koala} alt={'Koala'} />} description="Classic service desk" > Customer Feedback </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={ui} alt={'UI'} />} description="Classic software project" > Design System </ButtonItem> </Section> <Section hasSeparator> <ButtonItem>View all projects</ButtonItem> <ButtonItem>Create project</ButtonItem> </Section> </MenuGroup> </MenuGroupContainer> ); };

Scrollable sections

For menus with distinct sections, it's possible to have some scrollable sections.

Scrollable sections don't have as much visual affordance, and should be reserved for user-generated content where the number of menu items isn't known.

import React from 'react'; import ButtonItem from '@atlaskit/menu/button-item'; import MenuGroup from '@atlaskit/menu/menu-group'; import Section from '@atlaskit/menu/section'; import ImgIcon from '../common/img-icon'; import MenuGroupContainer from '../common/menu-group-container'; import battery from '../icons/battery.png'; import cloud from '../icons/cloud.png'; import koala from '../icons/koala.png'; import ui from '../icons/ui.png'; import wallet from '../icons/wallet.png'; export default (): React.JSX.Element => { return ( <MenuGroupContainer> <MenuGroup maxHeight={300}> <Section title="Recent" isScrollable> <ButtonItem iconBefore={<ImgIcon src={battery} alt="Battery" />} description="Next-gen software project" > Fabric Editor </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={cloud} alt="Cloud" />} description="Classic business project" > Content Services </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={wallet} alt="Wallet" />} description="Next-gen software project" > Trinity Mobile </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={koala} alt="Koala" />} description="Classic service desk" > Customer Feedback </ButtonItem> <ButtonItem iconBefore={<ImgIcon src={ui} alt="UI logo" />} description="Classic software project" > Design System </ButtonItem> </Section> <Section hasSeparator> <ButtonItem>View all projects</ButtonItem> <ButtonItem>Create project</ButtonItem> </Section> </MenuGroup> </MenuGroupContainer> ); };

Loading

To defer loading the entire menu, the contents can be rendered as skeleton placeholders while the items load asynchronously.

import React, { useEffect, useState } from 'react'; import { cssMap, jsx } from '@compiled/react'; import Button from '@atlaskit/button/default/button'; import StarStarredIcon from '@atlaskit/icon/core/star-starred'; import StarUnstarredIcon from '@atlaskit/icon/core/star-unstarred'; import ButtonItem from '@atlaskit/menu/button-item'; import HeadingItem from '@atlaskit/menu/heading-item'; import MenuGroup from '@atlaskit/menu/menu-group'; import Section from '@atlaskit/menu/section'; import SkeletonHeadingItem from '@atlaskit/menu/skeleton-heading-item'; import SkeletonItem from '@atlaskit/menu/skeleton-item'; import { type ButtonItemProps } from '@atlaskit/menu/types'; import { Box } from '@atlaskit/primitives/compiled/box'; import { Stack } from '@atlaskit/primitives/compiled/stack'; import { token } from '@atlaskit/tokens'; import MenuGroupContainer from '../common/menu-group-container'; import Invision from '../icons/invision'; import Portfolio from '../icons/portfolio'; import Slack from '../icons/slack'; import Tempo from '../icons/tempo'; const styles = cssMap({ iconContainer: { height: token('space.200'), width: token('space.200'), background: 'linear-gradient(180deg, #4E86EE 0%, #3562C1 100%), #4E86EE', borderRadius: token('radius.small'), }, buttonContainer: { display: 'flex', justifyContent: 'center', }, }); const Item = ({ isLoading, ...props }: ButtonItemProps & { isLoading?: boolean }) => { if (isLoading) { return <SkeletonItem hasIcon isShimmering />; } return <ButtonItem {...props} />; }; const Heading = ({ isLoading, ...props }: any) => { if (isLoading) { return <SkeletonHeadingItem isShimmering />; } return <HeadingItem {...props} />; }; export default (): React.JSX.Element => { const [isLoading, setIsLoading] = useState(true); const [retryLoading, setRetryLoading] = useState(true); useEffect(() => { if (!retryLoading) { return; } setIsLoading(true); setTimeout(() => { setRetryLoading(false); setIsLoading(false); }, 1500); }, [retryLoading]); return ( <Stack space="space.200"> <MenuGroupContainer> <MenuGroup> <Section aria-labelledby={isLoading ? '' : 'apps'}> <Heading aria-hidden id="apps" isLoading={isLoading}> Apps </Heading> <Item isLoading={isLoading} iconBefore={ <span css={styles.iconContainer}> <Portfolio color={token('color.icon.brand')} /> </span> } iconAfter={<StarStarredIcon color={token('color.icon.accent.orange')} label="" />} > Portfolio </Item> <Item isLoading={isLoading} iconBefore={<Tempo />} iconAfter={<StarStarredIcon color={token('color.icon.accent.orange')} label="" />} > Tempo timesheets </Item> <Item isLoading={isLoading} iconBefore={<Invision />} iconAfter={<StarUnstarredIcon label="" />} > Invision </Item> <Item isLoading={isLoading} iconBefore={<Slack />}> Slack </Item> </Section> <Section hasSeparator> <Item>Find new apps</Item> <Item>Manage your apps</Item> </Section> </MenuGroup> </MenuGroupContainer> <Box xcss={styles.buttonContainer}> <Button testId="toggle-loading" onClick={() => setRetryLoading(true)}> Reload </Button> </Box> </Stack> ); };
Was this page helpful?
We use this feedback to improve our documentation.
  • Design system
    • Get started
    • Foundations
    • Components
    • Rovo UI
    • Tools
    • Release phases
    • Contact us
© 2026 AtlassianTrademark, (opens new window)Privacy, (opens new window)License