Skip to content

Menu

Menu is the list of actions behind a button, such as the “…” on a pipeline stage or a table row. You describe the items as data and get the chosen value in onSelect.

import { Menu } from '@beyul/sulmu-ui'

Source · Figma

Last chosen: nothing yet

import {
Edit2Icon,
IconButton,
Menu,
MoreIcon,
Setting2Icon,
Text,
TrashIcon,
} from '@beyul/sulmu-ui'
import { useState } from 'react'
const items = [
{ value: 'automation', label: 'Stage Automation', icon: <Setting2Icon /> },
{ value: 'edit', label: 'Edit Stage', icon: <Edit2Icon /> },
{
value: 'delete',
label: 'Delete Stage',
icon: <TrashIcon />,
danger: true,
separatorBefore: true,
},
]
export default function Example() {
const [last, setLast] = useState('nothing yet')
return (
<>
<Menu
trigger={<IconButton aria-label="Stage actions" variant="secondary" icon={<MoreIcon />} />}
items={items}
onSelect={setLast}
/>
<Text textStyle="caption" tone="subtle" style={{ marginTop: 12 }}>
Last chosen: {last}
</Text>
</>
)
}

variant="inverse" is the dark glass panel used for the profile menu. header places content above the items, and keepOpen keeps the menu open after choosing an item.

import {
Avatar,
Button,
MagicStarIcon,
Menu,
MessageQuestionIcon,
Setting2Icon,
Switch,
} from '@beyul/sulmu-ui'
export default function Example() {
return (
<Menu
variant="inverse"
trigger={<Button variant="inverse">Account</Button>}
header={
<div style={{ display: 'flex', gap: 12, alignItems: 'center', minWidth: 220 }}>
<Avatar size="lg" name="Howard Sheldon" />
<div>
<div style={{ color: 'var(--su-colors-fg-inverse)', fontSize: 14 }}>Howard Sheldon</div>
<div style={{ fontSize: 12 }}>@Thenter888</div>
</div>
</div>
}
items={[
{ value: 'profile', label: 'Profile', icon: <Setting2Icon />, separatorBefore: true },
{ value: 'help', label: 'Help Center', icon: <MessageQuestionIcon /> },
{
value: 'dark',
label: 'Dark Mode',
icon: <MagicStarIcon />,
trailing: <Switch aria-label="Dark mode" />,
keepOpen: true,
},
{ value: 'logout', label: 'Log Out', separatorBefore: true },
]}
/>
)
}
PropTypeDefaultDescription
trigger*ReactElement<unknown, string | JSXElementConstructor<any>>-The element that opens the menu: a Button or IconButton.
items*MenuItem[]-
headerReactNode-Content above the items, e.g. the user's avatar and name.
variant"inverse" | "surface"surfacesurface (default) or inverse, the dark glass panel used for the profile menu.
onSelect((value: string) => void)-Called with the chosen item's value.
openboolean-The controlled open state of the menu
defaultOpenboolean-The initial open state of the menu when rendered. Use when you don't need to control the open state of the menu.
onOpenChange((details: OpenChangeDetails) => void)-Function called when the menu opens or closes

The remaining props of Ark UI’s Menu.Root are accepted too.

Field Type Description
value string Passed to onSelect when the item is chosen. Must be unique.
label ReactNode The item text.
icon ReactNode Shown before the label.
disabled boolean The item cannot be chosen.
danger boolean Destructive action, shown in the danger colour.
trailing ReactNode Shown at the right edge: a tick, a Switch, a count.
keepOpen boolean Keep the menu open after choosing this item (for toggles).
separatorBefore boolean Draw a separator line above this item.
  • trigger must be a single element that can take a ref and props: a Button or IconButton.
  • Arrow keys move through the items, Enter chooses, Escape closes and returns focus to the trigger.
  • A menu is for actions. To pick a value, use Select.