Menu
Menus display a list of up to 15 options when launched by an action or UI element like an icon or button.
Anatomy

- Container: Rectangular container that houses the icon and text for menu list items.
- Text: Text for indicating where the link leads to when the menu is clicked on. Text can overflow to the next line but avoid going over more than two lines of text.
- Icons: Icons are optional and can be positioned before or after the text.
Usage Guidance
- Popup Menus can appear next to, in front of, above, or below the element that launched them, such as Dropdown Buttons, Dropdown Icons, icon only Primary/Secondary/Tertiary Button variants or by right-clicking a contextual item.
- Popup Menus should overlap and visually look like they are in front of other UI elements. They should always be positioned within the viewable areas of the screen and be 8px away from the element that launched them.
- Popup Menus should always contain a list of menu selections, which are options users can choose from. The list should be scannable, kept as concise as possible, and written in title case instead of sentences.
- Consider how important each option is. The list of options should be sorted in a logical order, such as alphabetical, chronological, order of importance, and so on.
When to Use
- In most cases, as with Overflow Menus, where there aren’t enough space on screen to show all the actions, there could be between 1-7 items to choose from. However, there shouldn’t be more than 15 items listed at once on a single Popup Menu.
- When users must make a single selection from the list of options.
When to Use Something Else
- Consider using a Switch if the only options are yes or no.
- For a list between 2 to 7 predefined options, consider using a Radio input to select one option or Checkboxes to select multiple options. Radio and Checkbox groups display all options upfront and do not require the user to interact with the input to view the list of options.
- Use a Prompt when the number of list items is large or unknown. Prompts have search capabilities and folders which provide users with the means to browse options. Prompts can be configured to support single or multi-select.
Design Annotations for Accessibility
- Write an accessible name for icon-only button variants invoking menus.
- Declare whether any icons used in menu items are decorative, or require additional text alternatives.
Examples
Basic Example
Menu is typically triggered by an action such as pressing a button. The Menu comes with a
Target subcomponent and a Popup.
Selected:
import React from 'react';
import {Menu} from '@workday/canvas-kit-react/menu';
import {BodyText} from '@workday/canvas-kit-react/text';
export default () => {
const [selected, setSelected] = React.useState('');
return (
<Menu onSelect={data => setSelected(data.id)}>
<Menu.Target>Open Menu</Menu.Target>
<Menu.Popper>
<Menu.Card>
<Menu.List>
<Menu.Item>First Item</Menu.Item>
<Menu.Item>Second Item</Menu.Item>
<Menu.Divider />
<Menu.Item>Third Item (with a really, really, really long label)</Menu.Item>
<Menu.Item aria-disabled>Fourth Item</Menu.Item>
</Menu.List>
</Menu.Card>
</Menu.Popper>
<BodyText size="small" marginTop="s">
Selected: <span data-testid="output">{selected}</span>
</BodyText>
</Menu>
);
};
Menu will automatically focus on the cursor item (first item by default). The Menu uses a menu
model which composes a list model and a popup model and sets up accessibility features for you.
Context Menu
Selected:
import React from 'react';
import {Menu} from '@workday/canvas-kit-react/menu';
import {BodyText} from '@workday/canvas-kit-react/text';
export default () => {
const [selected, setSelected] = React.useState('');
return (
<Menu onSelect={data => setSelected(data.id)}>
<Menu.TargetContext>Right-click to Open Menu</Menu.TargetContext>
<Menu.Popper>
<Menu.Card>
<Menu.List>
<Menu.Item>First Item</Menu.Item>
<Menu.Item>Second Item</Menu.Item>
<Menu.Item>Third Item (with a really, really, really long label)</Menu.Item>
<Menu.Item>Fourth Item</Menu.Item>
</Menu.List>
</Menu.Card>
</Menu.Popper>
<BodyText size="small" marginTop="s">
Selected: <span data-testid="output">{selected}</span>
</BodyText>
</Menu>
);
};
Accessibility Note: This variation relies on the
contextmenubrowser event, which has varying levels of support across different operating systems. On Windows, this feature is better supported and users can typically trigger context menus using the Shift + F10 keyboard shortcut or the dedicated Context Menu key (if available on their keyboard). However, on macOS, context menu support is limited and may require users to enable specific accessibility settings in their system preferences to function properly. Consider providing alternative access methods for critical functionality.
Icons
Menu supports more complex children, including icons, but the text of the item will no longer be
known. In this case, add a data-text attribute to inform the collection system what the text of
the item is. The text is used for components that filter based on text. For example, a Select
component will jump to an item based on the keys the user types. If the user types “C”, the
component will jump to the first item that starts with a “C”. This functionality requires knowledge
about the text of the item.
Selected:
import React from 'react';
import {
setupIcon,
uploadCloudIcon,
userIcon,
taskContactIcon,
} from '@workday/canvas-system-icons-web';
import {Menu} from '@workday/canvas-kit-react/menu';
import {BodyText} from '@workday/canvas-kit-react/text';
export default () => {
const [selected, setSelected] = React.useState('');
return (
<Menu onSelect={data => setSelected(data.id)}>
<Menu.Target>Open Menu</Menu.Target>
<Menu.Popper>
<Menu.Card>
<Menu.List>
<Menu.Item data-text="First Item">
<Menu.Item.Icon icon={uploadCloudIcon} />
<Menu.Item.Text>First Item</Menu.Item.Text>
</Menu.Item>
<Menu.Item data-text="Second Item (with a really really really long label)">
<Menu.Item.Icon icon={setupIcon} />
<Menu.Item.Text>Second Item (with a really really really long label)</Menu.Item.Text>
</Menu.Item>
<Menu.Item aria-disabled data-text="Third Item">
<Menu.Item.Icon icon={uploadCloudIcon} />
<Menu.Item.Text>Third Item</Menu.Item.Text>
<Menu.Item.Icon icon={taskContactIcon} />
</Menu.Item>
<Menu.Item data-text="User">
<Menu.Item.Icon icon={userIcon} />
<Menu.Item.Text>User</Menu.Item.Text>
</Menu.Item>
<Menu.Divider />
<Menu.Item data-text="Fifth Item (with divider)">
<Menu.Item.Icon icon={taskContactIcon} />
<Menu.Item.Text>Fifth Item (with divider)</Menu.Item.Text>
</Menu.Item>
</Menu.List>
</Menu.Card>
</Menu.Popper>
<BodyText size="small" marginTop="s">
Selected: <span data-testid="output">{selected}</span>
</BodyText>
</Menu>
);
};
Accessibility Note: Icons in menu items do not inherently provide text alternatives to assistive technologies. However, in most cases, icons are used decoratively alongside text labels, and additional text alternatives are not necessary since the menu item text itself provides the accessible name.
Grouping
Grouping adds hierarchy and categorization to menu items. Group headers do not represent menu items and are not selectable with the keyboard or mouse.
Note: Grouping is not supported in virtual rendering. Menus by default have
shouldVirtualizeset tofalse. Setting totrueresults in unspecified behavior. We usereact-virtualwhich doesn’t support nested virtualization.
Selected:
import React from 'react';
import {Menu} from '@workday/canvas-kit-react/menu';
import {BodyText} from '@workday/canvas-kit-react/text';
export default () => {
const [selected, setSelected] = React.useState('');
return (
<>
<Menu onSelect={data => setSelected(data.id)}>
<Menu.Target>Open Menu</Menu.Target>
<Menu.Popper>
<Menu.Card>
<Menu.List>
<Menu.Group title="First Group">
<Menu.Item>First Item</Menu.Item>
<Menu.Item>Second Item</Menu.Item>
</Menu.Group>
<Menu.Group title="Second Group">
<Menu.Item>Third Item (with a really, really, really long label)</Menu.Item>
<Menu.Item aria-disabled>Fourth Item</Menu.Item>
</Menu.Group>
</Menu.List>
</Menu.Card>
</Menu.Popper>
<BodyText size="small" marginTop="s">
Selected: <span data-testid="output">{selected}</span>
</BodyText>
</Menu>
</>
);
};
Accessibility Note: Menu groups use
role="group"with appropriate labeling to provide semantic structure for assistive technologies. When navigating through grouped menu items, screen readers will announce the group label when users enter a new group, providing important context about the organization of the menu. Group headers are not part of the keyboard navigation sequence, allowing users to efficiently move between actionable menu items. This semantic grouping helps all users, including those using assistive technologies, understand the hierarchy and categorization of menu options.
Nested
Menus support nesting. If you only have a few items and not very many nesting levels, the menu can
be defined statically using JSX. A submenu is defined using the <Menu.Submenu> component. The
Submenu is implemented as a special Menu subcomponent. The API of the submenu is the same as the
Menu except the submenu’s target is also a menu item. The component is named TargetItem to
indicate this dual role.
Selected:
import React from 'react';
import {chevronRightSmallIcon} from '@workday/canvas-system-icons-web';
import {Menu} from '@workday/canvas-kit-react/menu';
import {BodyText} from '@workday/canvas-kit-react/text';
export default () => {
const [selected, setSelected] = React.useState('');
return (
<Menu
id="first-menu"
onSelect={data => {
setSelected(data.id);
}}
>
<Menu.Target>Open Menu</Menu.Target>
<Menu.Popper>
<Menu.Card>
<Menu.List>
<Menu.Item data-id="first-item">First Item</Menu.Item>
<Menu.Submenu id="second-menu">
<Menu.Submenu.TargetItem data-id="second-item">Second Item</Menu.Submenu.TargetItem>
<Menu.Submenu.Popper>
<Menu.Submenu.Card>
<Menu.Submenu.List>
<Menu.Submenu.Item data-id="first-sub-item">First Sub Item</Menu.Submenu.Item>
<Menu.Submenu.Item data-id="second-sub-item">First Sub Item</Menu.Submenu.Item>
<Menu.Submenu.Item data-id="third-sub-item">Third Sub Item</Menu.Submenu.Item>
<Menu.Submenu.Item data-id="fourth-sub-item">Fourth Sub Item</Menu.Submenu.Item>
</Menu.Submenu.List>
</Menu.Submenu.Card>
</Menu.Submenu.Popper>
</Menu.Submenu>
<Menu.Divider />
<Menu.Item data-id="third-item">
Third Item (with a really, really, really long label)
</Menu.Item>
<Menu.Item aria-disabled data-id="fourth-item">
Fourth Item
</Menu.Item>
</Menu.List>
</Menu.Card>
</Menu.Popper>
<BodyText size="small" marginTop="s">
Selected: <span data-testid="output">{selected}</span>
</BodyText>
</Menu>
);
};
Accessibility Note: When a menu item has an attached submenu, the
<Menu.Submenu.TargetItem>includesaria-haspopup="true"andaria-expanded={true | false}properties. These properties will alert screen reader users to the available submenu systems.
Nested Dynamic Items
Menu nesting is simpler with the dynamic API. In this example, a renderItem function is defined to
allow recursive nesting of items using a data structure you define. A submenu will inherit the
getId and getTextValue functions of the parent menu. While you can pass a specialize getId or
getTextValue function to each submenu, it may be simpler to use the same one for the menu and
submenus.
Selected:
import React from 'react';
import {Menu} from '@workday/canvas-kit-react/menu';
import {BodyText} from '@workday/canvas-kit-react/text';
import {system} from '@workday/canvas-tokens-web';
type Item = {
type?: 'item';
id: string;
label: string;
};
type SubmenuItem = {
id: string;
label: string;
type: 'submenu';
children: (Item | SubmenuItem)[];
};
// This is a user-defined object. The structure uses `id` for the item identifier which is the
// default key used by the collection system and therefore doesn't require a `getId` function to be
// passed to the model. The `label` isn't the standard text value used by the collection system, so
// a `getTextValue` function is required. The `type` and `children` aren't important at all to the
// menu and are used in the template by the user-defined `renderItem` function.
const items: (SubmenuItem | Item)[] = [
{id: 'first-item', label: 'First Item'},
{
id: 'second-item',
label: 'Second Item',
type: 'submenu',
children: [
{id: 'first-sub-item', label: 'First Sub Item'},
{
id: 'second-sub-item',
label: 'Second Sub Item',
type: 'submenu',
children: [
{id: 'first-sub-sub-item', label: 'First Sub Sub Item'},
{
id: 'second-sub-sub-item',
type: 'submenu',
label: 'Second Sub Sub Item',
children: [
{id: 'first-sub-sub-sub-item', label: 'First Sub Sub Sub Item'},
{
id: 'second-sub-sub-sub-item',
label: 'Second Sub Sub Sub Item',
},
{id: 'third-sub-sub-sub-item', label: 'Third Sub Sub Sub Item'},
{id: 'fourth-sub-sub-sub-item', label: 'Fourth Sub Sub Sub Item'},
],
},
{id: 'third-sub-sub-item', label: 'Third Sub Sub Item'},
{id: 'fourth-sub-sub-item', label: 'Fourth Sub Sub Item'},
],
},
{id: 'third-sub-item', label: 'Third Sub Item'},
{id: 'fourth-sub-item', label: 'Fourth Sub Item'},
],
},
{id: 'third-item', label: 'Third Item'},
{id: 'fourth-item', label: 'Fourth Item'},
];
export default () => {
const [selected, setSelected] = React.useState('');
// defining this inline function allows use to recurse any nesting level defined by the `items`
// array.
function renderItem(item: SubmenuItem | Item) {
if (item.type === 'submenu') {
return (
<Menu.Submenu id={item.id} items={item.children}>
<Menu.Submenu.TargetItem>{item.label}</Menu.Submenu.TargetItem>
<Menu.Submenu.Popper>
<Menu.Submenu.Card>
<Menu.Submenu.List>{renderItem}</Menu.Submenu.List>
</Menu.Submenu.Card>
</Menu.Submenu.Popper>
</Menu.Submenu>
);
}
return <Menu.Item>{item.label}</Menu.Item>;
}
return (
<Menu
items={items}
id="first-menu"
getTextValue={item => item.label}
onSelect={data => {
setSelected(data.id);
}}
>
<Menu.Target>Open Menu</Menu.Target>
<Menu.Popper>
<Menu.Card>
<Menu.List>{renderItem}</Menu.List>
</Menu.Card>
</Menu.Popper>
<BodyText size="small" cs={{marginBlockStart: system.space.x4}}>
Selected: <span data-testid="output">{selected}</span>
</BodyText>
</Menu>
);
};
Accessibility
Our Menu component is based on the Menu Button pattern on the ARIA Authoring Practices Guide from the W3C and relies on the roving tabindex technique for managing focus within the opened menu. This means that the minimum requirements for screen reader support and keyboard navigation are included in the component.
Menu Button Pattern | APG | WAI | W3C
- The
<Menu.Target>sub-component usesaria-haspopup="true"andaria-expanded={true | false}properties. This benefits screen reader users by indicating when a button element has an attached menu. - The
<Menu.List>sub-component usesrole="menu"and<Menu.Item>usesrole="menuitem"ARIA roles. These roles allow screen readers to pass through arrow key events to the web application. - The
<Menu.List>sub-component includes anaria-labelledbyID reference to the<Menu.Target>sub-component. This assigns a label to the menu for context.
Navigation
- Enter or Space: When focused on the menu button, opens the menu and moves focus to the first menu item. When focused on a menu item, activates the item and closes the menu
- Escape: Closes the menu and returns focus to the menu button
- Up & Down Arrow: Moves focus up and down the menu items
- Home & End: Moves focus to the first or last menu item
- Right & Left Arrow: When focused on a menu item with a submenu, opens the submenu and moves focus to the first item in the submenu or closes the submenu and returns focus to the parent menu item
Screen Reader Experience
- The menu button will be announced with its label text followed by the button role, a notification that it has a popup menu, and the current state of the menu (For example: “Actions, button, menu popup, collapsed”)
- Opening the Menu: When the menu button is activated, screen readers will announce the menu opening, the number of menu items available, and the currently focused item (For example: “Actions, menu, First Action, menu item, 1 of 4.”)
- Navigating Menu Items: As focus moves between menu items, screen readers will announce the item name and its position in the list (For example: “Second Action, menu item, 2 of 4.”)
- Menu Items with Submenus: When focused on a menu item that has a submenu, screen readers will announce that it has a submenu and provide the expanded/collapsed state (For example: “More Actions, menu item, has submenu, collapsed, 3 of 4.”)
Component API
Menu
Menu is a combination of a popup and a list. It usually has some type of target element that
expands/collapses the menu and a menu role and and several menuitem roles. Focus is managed
using roving tabindex for maximum
compatibility. A Menu can have two modes: single and multiple. This mode determines both
how many items can be selected as well as the default behavior when a menuitem is clicked. For
the single mode, selecting a menuitem will select and close the menu. For the multiple
mode, clicking a menuitem will toggle selection and will not close the menu.
<Menu>
<Menu.Target>Open</Menu.Target>
<Menu.Popper>
<Menu.Card>
<Menu.List>
<Menu.Item data-id="first">First Item</Menu.Item>
<Menu.Item data-id="second">Second Item</Menu.Item>
</Menu.List>
</Menu.Card>
</Menu.Popper>
</Menu>
Props
Props extend from . If a model is passed, props from MenuModelConfig are ignored.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | The contents of the Menu. Can be | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
Menu.Target
Menu.Target is similar to all types. The component only
provides behavior and no styling. The as prop is used to determine which component is
rendered. This component should forward the ref and apply any additional props directly to
an element. The default as is a {@link SecondaryButton }. Any Canvas Kit component should
work with an as.
An example changing to a {@link PrimaryButton }
<Menu.Target as={PrimaryButton}>Primary Button Text</Menu.Target>
This element will apply aria-haspopup and aria-expanded to inform screen readers there's
a popup associated with the element.
Props
Props extend from . Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | ||
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | |
ref | React.Ref<R = > | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useMenuTarget
(
unknown {
"kind": "unknown",
"value": "unknown",
"text": "useMenuTargetBase"
},
)Menu.Card
The menu card is a non-semantic element used to give the dropdown menu its distinct visual cue that the dropdown menu is floating above other content. A menu card usually contains a menu list, but can also contain other elements like a header or footer.
Layout Component
Menu.Card supports all props from thelayout component.
Props
Props extend from div. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | Children of the Card. Should contain a | |
variant | 'borderless' | 'filled' | The variant of the Card. Can be | 'default' |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
Menu.List
The menu list follows the Collections API. A list can either contain static items
or a render prop and items to the model.
const MyComponent = () => {
const model = useMenuModel({
items: [
{ id: 'first', text: 'First Item' },
{ id: 'second', text: 'Second Item' },
]
})
return (
<Menu model={model}>
<Menu.List>
{(item) => <Menu.Item data-id={item.id}>{item.text}</Menu.Item>}
</Menu.List>
</Menu>
)
}
Layout Component
Menu.List supports all props from thelayout component.
Props
Props extend from div. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | | The label text of the MenuList. | |
marginY | | Set the margin top and bottom of the list box. You must use this prop and not style any other way. The
| |
marginTop | | Set the margin top of the list box. You must use this prop and not style any other way. The
| |
marginBottom | | Set the margin bottom of the list box. You must use this prop and not style any other way. The
| |
cs | | The | |
columnCount | number | If this is set it will cause a wrapping of a list that will turn it into a grid | 0 |
id | string | IDREF of the list. Children ids can be derived from this id | |
navigation | | Controls the state changes when the user sends navigation events to the model. For example,
when the user hits the "right" arrow, a behavior hook will determine directionality
(left-to-right or right-to-left) and call the correct navigation method. In our example, a
left-to-right language would send a An example override might be a tab list with an overflow menu that is meant to be transparent to screen reader users. This would require the overflow menu to accept both up/down keys as well as left/right keys to give a more consistent experience to all users. | |
shouldVirtualize | true | ||
selection | | ||
pageSize | number | Controls how much a pageUp/pageDown navigation request will jump. If not provided, the size of the list and number of items rendered will determine this value. | |
getId | (item: ) => string | Optional function to return an id of an item. If not provided, the default function will
return the | |
getTextValue | (item: ) => string | Optional function to return the text representation of an item. If not provided, the default
function will return the | |
defaultItemHeight | number | Best guess to the default item height for virtualization. Getting this number correct avoids a rerender while the list is initializing. | 50 |
nonInteractiveIds | string[] | Array of all ids which are currently disabled. This is used for navigation to skip over items which are not focusable. | |
orientation | | The orientation of a list of items. Values are either | 'vertical' |
items | [] | Optional array of items. If provided, use a render prop for list children instead of static
children. If the shape of each item object does not have an | |
initialCursorId | string | string[] | Initial cursor position. If not provided, the cursor will point to the first item in the list | |
initialSelectedIds | | ||
initialUnselectedIds | string[] | ||
UNSTABLE_parentModel | { | ||
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useMenuList
(
(
model: ,
elemProps: {},
ref: React.Ref
) => {
role: 'menu';
aria-labelledby: string;
aria-orientation: 'horizontal' | 'vertical';
},
,
)Menu.Item
A Menu.Item has an optional data-id prop that identifies the item in the Menu.List and
will be passed to the optional onSelect callback of the Menu model. A Menu.Item can
contain any HTML. If more complex HTML is provided, add data-text to the Menu.Item
component if using the static API. If you're using the dynamic API, pass getTextValue to
the model.
Props
Props extend from button. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
index | number | Optionally pass index to menu item. This should be done if | |
children | ReactNode | The label text of the MenuItem. | |
data-id | string | The name of the menu item. This name will be used in the | |
aria-disabled | boolean |
| |
isDisabled | boolean | If true, set the StyledMenuItem to the disabled state so it is not clickable. | false |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | button |
ref | React.Ref<R = button> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useMenuItem
(
(
model: ,
elemProps: {},
ref: React.Ref
) => {
role: 'menuitem';
onMouseDown: (event: ) => void;
onClick: ((event: SyntheticEvent) => void) | undefined;
},
,
,
,
,
)Menu.Item.Icon
Basic type information:
MenuItemIconMenu.Item.Text
Basic type information:
MenuItemTextMenu.Group
This component references the component.
Menu.Option
A Menu.Option is similar to the Menu.Item, but has a role=option and works with
aria-activedescendant and is selectable with a selected checkmark. It adds the
aria-selected="true/false" attribute. Menu.Option requires much more accessibility
behavior composed into the Menu.Target and Menu.List component. The Combobox and
Select components make use of the Menu.Option. See those components for a better idea of
how behavior is composed.
Props
Props extend from li. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
index | number | Optionally pass index to menu item. This should be done if | |
children | ReactNode | The label text of the MenuItem. | |
data-id | string | The name of the menu item. This name will be used in the | |
aria-disabled | boolean |
| |
isDisabled | boolean | If true, set the StyledMenuItem to the disabled state so it is not clickable. | false |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | li |
ref | React.Ref<R = li> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useMenuOption
(
(
model: ,
elemProps: {
data-id: string;
},
ref: React.Ref
) => {
role: 'option';
aria-selected: boolean;
onMouseDown: (event: <>) => void;
},
,
)Menu.Option.Text
Basic type information:
MenuOptionTextMenu.Divider
Props
Props extend from hr. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
cs | | The | |
children | React.ReactNode | ||
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | hr |
ref | React.Ref<R = hr> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If |
Menu.TargetContext
A Menu.TargetContext is the same as a , except it adds a
context event handler instead of a click handler to trigger context menus.
Props
Props extend from . Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | ||
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | |
ref | React.Ref<R = > | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useMenuTargetContext
(
unknown {
"kind": "unknown",
"value": "unknown",
"text": "useMenuTargetBase"
},
)Menu.Popper
The "Popper" of a menu. The popper will appear around the . It
renders a div element that is portalled to the document.body which is controlled by the
{@link PopupStack }. The PopupStack is not part of React. This means no extra props given to
this component will be forwarded to the div element, but the ref will be forwarded.
Props
Props extend from div. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
anchorElement | <Element> | Element | null | The reference element used to position the Popper. Popper content will try to follow the
| |
children | ((props: { | The content of the Popper. If a function is provided, it will be treated as a Render Prop and
pass the | |
getAnchorClientRect | () => | When provided, this optional callback will be used to determine positioning for the Popper element
instead of calling | |
open | boolean | Determines if | true |
placement | | The placement of the | |
fallbackPlacements | [] | Define fallback placements by providing a list of | |
onPlacementChange | (placement: ) => void | A callback function that will be called whenever PopperJS chooses a placement that is different
from the provided | |
popperOptions | <PopperOptions> | The additional options passed to the Popper's | |
portal | boolean | If false, render the Popper within the
DOM hierarchy of its parent. A non-portal Popper will constrained by the parent container
overflows. If you set this to | true |
popperInstanceRef | Ref<> | Reference to the PopperJS instance. Useful for making direct method calls on the popper
instance like | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
usePopupPopper
Adds the necessary props to a {@link Popper } component. Used by the
subcomponent.
(
model: ,
elemProps: {},
ref: React.Ref
) => {
open: boolean;
anchorElement: <>;
ref: (instance: | null) => void;
onPlacementChange: (placement: ) => void;
}Menu.Submenu
Submenu should be put in place of a Menu.Item. It will render a menu item that is the target
for the submenu card.
<Menu.Item>First Item</Menu.Item>
<Menu.Submenu>
<Menu.Submenu.TargetItem>Second Item</Menu.Submenu.TargetItem>
<Menu.Submenu.Popper>
<Menu.Submenu.Card>
<Menu.Submenu.List>
<Menu.Submenu.Item data-id="first">First Sub Item</Menu.Submenu.Item>
<Menu.Submenu.Item data-id="second">Second Sub Item</Menu.Submenu.Item>
</Menu.Submenu.List>
</Menu.Submenu.Card>
</Menu.Submenu.Popper>
</Menu.Submenu>
</Menu.Item>Third Item</Menu.Item>
Props
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | The contents of the Menu. Can be | |
mode | 'multiple' | 'single' | Determines the default selection manager used as well as if the menu closes when an item is selected | |
shouldVirtualize | false | ||
returnFocusRef | <any> | undefined | Optional reference to an element that should receive focus when a popup is hidden. If left
blank, focus will return to the | |
initialFocusRef | <any> | undefined | Optional reference to an element that should receive focus when a popup is shown. If left blank, focus will be moved to the first focusable element inside the popup. | |
id | string | ID reference of the list. Children ids can be derived from this id | |
initialVisibility | | The initial visibility of the disclosed content | 'hidden' |
initialSelectedIds | | ||
initialUnselectedIds | string[] | ||
selection | | ||
initialCursorId | string | string[] | Initial cursor position. If not provided, the cursor will point to the first item in the list | |
columnCount | number | If this is set it will cause a wrapping of a list that will turn it into a grid | 0 |
navigation | | Controls the state changes when the user sends navigation events to the model. For example,
when the user hits the "right" arrow, a behavior hook will determine directionality
(left-to-right or right-to-left) and call the correct navigation method. In our example, a
left-to-right language would send a An example override might be a tab list with an overflow menu that is meant to be transparent to screen reader users. This would require the overflow menu to accept both up/down keys as well as left/right keys to give a more consistent experience to all users. | |
pageSize | number | Controls how much a pageUp/pageDown navigation request will jump. If not provided, the size of the list and number of items rendered will determine this value. | |
getId | (item: ) => string | Optional function to return an id of an item. If not provided, the default function will
return the | |
getTextValue | (item: ) => string | Optional function to return the text representation of an item. If not provided, the default
function will return the | |
nonInteractiveIds | string[] | Array of all ids which are currently disabled. This is used for navigation to skip over items which are not focusable. | |
orientation | | The orientation of a list of items. Values are either | 'vertical' |
defaultItemHeight | number | Best guess to the default item height for virtualization. Getting this number correct avoids a rerender while the list is initializing. | 50 |
items | [] | Optional array of items. If provided, use a render prop for list children instead of static
children. If the shape of each item object does not have an | |
UNSTABLE_parentModel | { | ||
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
Menu.Submenu.Card
The menu card is a non-semantic element used to give the dropdown menu its distinct visual cue that the dropdown menu is floating above other content. A menu card usually contains a menu list, but can also contain other elements like a header or footer.
Layout Component
Menu.Card supports all props from thelayout component.
Props
Props extend from div. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | Children of the Card. Should contain a | |
variant | 'borderless' | 'filled' | The variant of the Card. Can be | 'default' |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
Menu.Submenu.List
The menu list follows the Collections API. A list can either contain static items
or a render prop and items. It is recommended that the items comes from a nested
JavaScript object.
Layout Component
Menu.List supports all props from thelayout component.
Props
Props extend from div. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | | The label text of the MenuList. | |
marginY | | Set the margin top and bottom of the list box. You must use this prop and not style any other way. The
| |
marginTop | | Set the margin top of the list box. You must use this prop and not style any other way. The
| |
marginBottom | | Set the margin bottom of the list box. You must use this prop and not style any other way. The
| |
cs | | The | |
columnCount | number | If this is set it will cause a wrapping of a list that will turn it into a grid | 0 |
id | string | IDREF of the list. Children ids can be derived from this id | |
navigation | | Controls the state changes when the user sends navigation events to the model. For example,
when the user hits the "right" arrow, a behavior hook will determine directionality
(left-to-right or right-to-left) and call the correct navigation method. In our example, a
left-to-right language would send a An example override might be a tab list with an overflow menu that is meant to be transparent to screen reader users. This would require the overflow menu to accept both up/down keys as well as left/right keys to give a more consistent experience to all users. | |
shouldVirtualize | true | ||
selection | | ||
pageSize | number | Controls how much a pageUp/pageDown navigation request will jump. If not provided, the size of the list and number of items rendered will determine this value. | |
getId | (item: ) => string | Optional function to return an id of an item. If not provided, the default function will
return the | |
getTextValue | (item: ) => string | Optional function to return the text representation of an item. If not provided, the default
function will return the | |
defaultItemHeight | number | Best guess to the default item height for virtualization. Getting this number correct avoids a rerender while the list is initializing. | 50 |
nonInteractiveIds | string[] | Array of all ids which are currently disabled. This is used for navigation to skip over items which are not focusable. | |
orientation | | The orientation of a list of items. Values are either | 'vertical' |
items | [] | Optional array of items. If provided, use a render prop for list children instead of static
children. If the shape of each item object does not have an | |
initialCursorId | string | string[] | Initial cursor position. If not provided, the cursor will point to the first item in the list | |
initialSelectedIds | | ||
initialUnselectedIds | string[] | ||
UNSTABLE_parentModel | { | ||
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useMenuList
(
(
model: ,
elemProps: {},
ref: React.Ref
) => {
role: 'menu';
aria-labelledby: string;
aria-orientation: 'horizontal' | 'vertical';
},
,
)Menu.Submenu.Item
If the static API is used, a data-id prop should be used to identify the item. If you're
using the dynamic API, pass a getId and getTextValue to the parent Menu the model.
Props
Props extend from button. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
index | number | Optionally pass index to menu item. This should be done if | |
children | ReactNode | The label text of the MenuItem. | |
data-id | string | The name of the menu item. This name will be used in the | |
aria-disabled | boolean |
| |
isDisabled | boolean | If true, set the StyledMenuItem to the disabled state so it is not clickable. | false |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | button |
ref | React.Ref<R = button> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useMenuItem
(
(
model: ,
elemProps: {},
ref: React.Ref
) => {
role: 'menuitem';
onMouseDown: (event: ) => void;
onClick: ((event: SyntheticEvent) => void) | undefined;
},
,
,
,
,
)Menu.Submenu.Item.Icon
Basic type information:
MenuItemIconMenu.Submenu.Item.Text
Basic type information:
MenuItemTextMenu.Submenu.TargetItem
The Submenu.TargetItem is similar to the Menu.Item, but represents both the target for
the submenu and the item in the menu list. This should only be used once per <Menu.Submenu>
component.
Props
Props extend from button. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useSubmenuTargetItem
(
,
,
,
(
model: ,
elemProps: {},
ref: React.Ref
) => {
ref: (instance: | null) => void;
},
,
(
model: ,
elemProps: {},
ref: React.Ref
) => {
id: string;
role: 'menuitem';
aria-haspopup: 'true';
aria-expanded: boolean;
onMouseDown: (event: ) => void;
onMouseEnter: (event: ) => void;
onMouseLeave: () => void;
onClick: (event: ) => void;
data-has-children: true;
onKeyDown: (event: ) => void;
}
)Menu.Submenu.Group
This component references the component.
Menu.Submenu.Option
A Menu.Option is similar to the Menu.Item, but has a role=option and works with
aria-activedescendant and is selectable with a selected checkmark. It adds the
aria-selected="true/false" attribute. Menu.Option requires much more accessibility
behavior composed into the Menu.Target and Menu.List component. The Combobox and
Select components make use of the Menu.Option. See those components for a better idea of
how behavior is composed.
Props
Props extend from li. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
index | number | Optionally pass index to menu item. This should be done if | |
children | ReactNode | The label text of the MenuItem. | |
data-id | string | The name of the menu item. This name will be used in the | |
aria-disabled | boolean |
| |
isDisabled | boolean | If true, set the StyledMenuItem to the disabled state so it is not clickable. | false |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | li |
ref | React.Ref<R = li> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useMenuOption
(
(
model: ,
elemProps: {
data-id: string;
},
ref: React.Ref
) => {
role: 'option';
aria-selected: boolean;
onMouseDown: (event: <>) => void;
},
,
)Menu.Submenu.Option.Text
Basic type information:
MenuOptionTextMenu.Submenu.Divider
Props
Props extend from hr. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
cs | | The | |
children | React.ReactNode | ||
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | hr |
ref | React.Ref<R = hr> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If |
Menu.Submenu.Popper
The "Popper" of a menu. The popper will appear around the . It
renders a div element that is portalled to the document.body which is controlled by the
{@link PopupStack }. The PopupStack is not part of React. This means no extra props given to
this component will be forwarded to the div element, but the ref will be forwarded.
Props
Props extend from div. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
anchorElement | <Element> | Element | null | The reference element used to position the Popper. Popper content will try to follow the
| |
children | ((props: { | The content of the Popper. If a function is provided, it will be treated as a Render Prop and
pass the | |
getAnchorClientRect | () => | When provided, this optional callback will be used to determine positioning for the Popper element
instead of calling | |
open | boolean | Determines if | true |
placement | | The placement of the | |
fallbackPlacements | [] | Define fallback placements by providing a list of | |
onPlacementChange | (placement: ) => void | A callback function that will be called whenever PopperJS chooses a placement that is different
from the provided | |
popperOptions | <PopperOptions> | The additional options passed to the Popper's | |
portal | boolean | If false, render the Popper within the
DOM hierarchy of its parent. A non-portal Popper will constrained by the parent container
overflows. If you set this to | true |
popperInstanceRef | Ref<> | Reference to the PopperJS instance. Useful for making direct method calls on the popper
instance like | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useMenuPopper
Model
useMenuModel
useMenuModel (config: ): Specifications
Content Guidelines
- When writing Menu list items, refer to the Menus section of the Content Style Guide.
Anatomy

- Container: A dynamic and lightweight container that houses icons and list items.
- Icon (Optional): Descriptive iconography that precedes and supplements the list item.
- List Item: Text for a menu item.
- Divider (Optional): A break in menu items to group related items or differentiate unrelated items.
Usage Guidance
Item Prominence
Within a Menu, the most frequently used items should be in the most prominent location at the top.

Iconography Usage
Use meaningful supplementary icons to reinforce the Menu item’s title and improve scannability
![]()
Sectioning
Adding titles to Menu sections increases visual noise on a screen.

Do
Use a divider to differentiate sections as necessary.

Don't
Title Menu sections unless absolutely necessary.
UI State Changes
Confusion between when to use a Menu versus an Action Sheet is common. Usage is very context dependent and should be consistent in a flow.

Don't
Link between the Menu and Action Sheet, as it may lead to a contextually disorienting experience for the user. Use either the menu or the action sheet in one flow.
When to Use
- Use Menus to display a list of options to a user when contextual orientation is valuable in understanding the potential options.
- Use Menus to limit the number of screen-related actions required for a user to reach their end destination.
When to Consider Something Else
- Consider using an Action Sheet if the complexity behind a set of options cannot be simplified into a menu such as when additional actions like filtering appear immediately after a selection.
- Consider using an Action Sheet throughout a flow instead if a need arises to switch between a Menu and Action Sheet. This can prevent a potentially disorienting experience.
Behaviors
Pressed State

Disabled State

Selection State
Selection states delineate a pre-selected item in a menu from its peers, indicating to users the current selection within the interface. Selection states in the menu are often used in navigation (e.g., the dropdown navigation paradigm) to indicate current location within a flow.

Placement
Menus should generally be positioned near the edges or center of the screen, as they obscure other permanent UI elements on the screen when open. Menus should appear below (such as the top of screen), above (such as the bottom of screen), or on top of (such as the center of screen) the item that generates them.
API Guidelines
Methods
Class name: MenuConfigurable Module name: UIComponentsPlugin
public init(
featureData: FeatureMetricsData,
items: [ContextMenuRowOptionModel],
localizer: LocalizationAdapting,
iconAccessibilityLabel: String? = nil,
buttonVariant: ButtonVariant = .tertiary,
buttonView: ButtonView,
showingPopup: Binding<Bool>,
menuAlignment: PopUpContextMenuAlignment = .standard
)Parameters
| Name | Description | Default values |
|---|---|---|
| featureData | the feature name/context and the screen ID in which the component appears. | |
| items | List of ContextMenuRowOptionModel. | |
| localizer | localizer to translate default a11y strings. | |
| iconAccessibilityLabel | replaces button accessibility label if passed in; defaults to “related actions”. | nil |
| buttonVariant | styling of trigger button - primary, secondary, tertiary; deafults to tertiary. | .tertiary |
| buttonView | view that trigger button displays. | |
| showingPopup | binding Bool to trigger menu to appear programmatically. | |
| menuAlignment | PopupContextMenuAlignment which allows the consumer to set that they want the menu to align. Due to how the position modifier works, this can end up with the menu attempting to render partly outside the screen. If it detects that, it will print an error message and use the standard positioning/alignment. Default is standard. | .standard |
Content Guidelines
- Appropriate content within a Menu should enable users to access actions most relevant to their task at hand. Using Menus as a way to hide infrequently used information is not recommended.
- Keep menus as concise as possible and use meaningful supplementary icons.
- When writing menu list items, refer to the Menus section of the Content Style Guide.
Anatomy

- Container: A dynamic and lightweight container that houses icons and list items.
- Icon (Optional): Descriptive iconography that precedes and supplements the list item.
- List Item: Text for a menu item.
- Divider (Optional): A break in menu items to group related items or differentiate unrelated items.
Usage Guidance
Item Prominence
Within a Menu, the most frequently used items should be in the most prominent location at the top.

Iconography Usage
Use meaningful supplementary icons to reinforce the Menu item’s title and improve scannability
![]()
Sectioning
Adding titles to Menu sections increases visual noise on a screen.

Do
Use a divider to differentiate sections as necessary.

Don't
Title Menu sections unless absolutely necessary.
UI State Changes
Confusion between when to use a Menu versus an Action Sheet is common. Usage is very context dependent and should be consistent in a flow.

Don't
Link between the Menu and Action Sheet, as it may lead to a contextually disorienting experience for the user. Use either the menu or the action sheet in one flow.
When to Use
- Use Menus to display a list of options to a user when contextual orientation is valuable in understanding the potential options.
- Use Menus to limit the number of screen-related actions required for a user to reach their end destination.
When to Consider Something Else
- Consider using an Action Sheet if the complexity behind a set of options cannot be simplified into a menu such as when additional actions like filtering appear immediately after a selection.
- Consider using an Action Sheet throughout a flow instead if a need arises to switch between a Menu and Action Sheet. This can prevent a potentially disorienting experience.
Behaviors
Pressed State

Disabled State

Selection State
Selection states delineate a pre-selected item in a menu from its peers, indicating to users the current selection within the interface. Selection states in the menu are often used in navigation (e.g., the dropdown navigation paradigm) to indicate current location within a flow.

Placement
Menus should generally be positioned near the edges or center of the screen, as they obscure other permanent UI elements on the screen when open. Menus should appear below (such as the top of screen), above (such as the bottom of screen), or on top of (such as the center of screen) the item that generates them.
API Guidelines
Methods
fun MenuUiComponent(
modifier: Modifier = Modifier,
menuItems: List<DisplayableMenuItem>,
alignment: MenuAlignment = MenuAlignment.Default,
buttonView: @Composable (MenuController) -> Unit
)Parameters
| Name | Description |
|---|---|
| menuItems | List of [DisplayableMenuItem] to be displayed in the menu. |
| alignment | Aligns the DropdownMenu. [MenuAlignment.Default] uses the android [androidx.compose.material.DropdownMenu] alignment which aligns the dropdown to the leading edge, if the dropdown doesn’t have enough space it is trailing edge aligned. [MenuAlignment.Center] aligns the DropdownMenu to the center of the [buttonView]. [MenuAlignment.CenterScreen] aligns the DropdownMenu to center of the screen. |
| buttonView | Composable to be used as the trigger to open the menu. |
Content Guidelines
- Appropriate content within a Menu should enable users to access actions most relevant to their task at hand. Using Menus as a way to hide infrequently used information is not recommended.
- Keep menus as concise as possible and use meaningful supplementary icons.
- When writing menu list items, refer to the Menus section of the Content Style Guide.
Can't Find What You Need?
Check out our FAQ section which may help you find the information you're looking for. For further information, contact the #ask-canvas-design or #ask-canvas-kitchannels on Slack.