Examples
A simple menu
<Menu> <MenuTrigger> Menu </MenuTrigger> <MenuContent> <MenuItem value="1"> Item 1 </MenuItem> <MenuItem value="2"> Item 2 </MenuItem> <MenuItem value="3"> Item 3 </MenuItem> <MenuItem value="4"> Item 4 </MenuItem> </MenuContent> </Menu>
Different variants of menu
<Stack flexDirection="row" gap={2}> <Menu variant="core"> <MenuTrigger> Core </MenuTrigger> <MenuContent> <MenuItem value="1"> Item 1 </MenuItem> </MenuContent> </Menu> <Menu variant="floating"> <MenuTrigger> Floating </MenuTrigger> <MenuContent> <MenuItem value="1"> Item 1 </MenuItem> </MenuContent> </Menu> <Menu variant="accent"> <MenuTrigger> Accent </MenuTrigger> <MenuContent> <MenuItem value="1"> Item 1 </MenuItem> </MenuContent> </Menu> </Stack>
Submenues allow you to group actions that are related, but adds complexity to the menu. Avoid using more than two levels of submenues.
<Menu> <MenuTrigger> Menu </MenuTrigger> <MenuContent> <MenuItem value="1"> Item 1 </MenuItem> <Menu> <MenuTriggerItem value="2" rightIcon={<DropdownRightOutline24Icon />}> Item 2 </MenuTriggerItem> <MenuContent> <MenuItem value="submenu1">Submenu item 1</MenuItem> <MenuItem value="submenu2">Submenu item 2</MenuItem> </MenuContent> </Menu> </MenuContent> </Menu>
Menu with icons in the items
<Menu> <MenuTrigger> Menu </MenuTrigger> <MenuContent> <MenuItem value="1" leftIcon={<StarsOutline24Icon />}> Item 1 </MenuItem> <MenuItem value="2" rightIcon={<StarsOutline24Icon />}> Item 2 </MenuItem> <MenuItem value="3" leftIcon={<StarsOutline24Icon />} rightIcon={<StarsOutline24Icon />}> Item 3 </MenuItem> </MenuContent> </Menu>
Items in a menu can be organized into groupes to make the menu more manageable and easier to read.
<Menu> <MenuTrigger> Menu </MenuTrigger> <MenuContent> <MenuItemGroup label="Gruppe 1"> <MenuItem value="1"> value 1</MenuItem> <MenuItem value="2"> value 2 </MenuItem> </MenuItemGroup> <MenuSeparator /> <MenuItemGroup label="Gruppe 2"> <MenuItem value="3"> value 3</MenuItem> <MenuItem value="4"> value 4 </MenuItem> </MenuItemGroup> </MenuContent> </Menu>
Checkbox-items makes it easier to make filters for complex user interfaces, for examples tables.
() => { const [checkedValues, setCheckedValues] = React.useState<string[]>(["autosave"]) const items = [ { title: "Autosave", value: "autosave" }, { title: "Detect Language", value: "detect-language" }, { title: "Spellcheck", value: "spellcheck" }, ] const toggleValue = (value: string) => { setCheckedValues(prev => prev.includes(value) ? prev.filter(v => v !== value) : [...prev, value] ) } const isChecked = (value: string) => checkedValues.includes(value) return ( <Menu> <MenuTrigger> Features </MenuTrigger> <MenuContent> <MenuItemGroup label="Features"> {items.map(({ title, value }) => ( <MenuCheckboxItem key={value} value={value} checked={isChecked(value)} onCheckedChange={() => toggleValue(value)} > {title} </MenuCheckboxItem> ))} </MenuItemGroup> </MenuContent> </Menu> ) }
In addition to checkboxes, menues can have radioitems that also can be used to easier create filters.
() => { const [value, setValue] = React.useState("asc") const items = [ { label: "Ascending", value: "asc" }, { label: "Descending", value: "desc" }, ] return <Stack textAlign="center"> <Menu> <MenuTrigger>Singleselect</MenuTrigger> <MenuContent> <MenuItemGroup label="Features"> <MenuRadioItemGroup value={value} onValueChange={(e) => setValue(e.value)} > {items.map((item) => ( <MenuRadioItem key={item.value} value={item.value}> {item.label} </MenuRadioItem> ))} </MenuRadioItemGroup> </MenuItemGroup> </MenuContent> </Menu> </Stack>}
Guidelines
The Menu component provides an accessible, structured way to present contextual actions or options to users without overwhelming the interface. It is ideal when you want to group related commands behind a single trigger.
In addition to simple action items, the menu can also present more complex option groups like single‑select radio lists, or multi‑select checkbox lists. This makes it suitable for settings menus, or sorting/filtering controls.
Secondary actions
Menues should only contain secondary actions that are not critical and necessary to be visible for the user at all times.
Grouping of items
Checkbox-items and radio-items should always be grouped and wrapped in a MenuItemGroup with a label describes their purpose/context. If the menu only consists of checkbox-items or radio-items, a label is not necessary if the menu trigger has a descriptive name.
Submenues
Submenues can be useful to group actions that are related, but it adds complexity to the menu.
Avoid using more than 2 levels of submenues.
Code
<Menu />
import { Menu } from "@vygruppen/spor-react";
Props
Name | Type | Required? | Description |
|---|---|---|---|
children | React.ReactNode | Children should contain CardSelectTrigger and CardSelectContent | |
open | boolean | ||
onOpenChange | (details: OpenChangeDetails) => void | ||
positioning | PositioningOptions | Decides the placement of the menu. Example: {{ placement: "right-start" }} |
<MenuTrigger />
import { MenuTrigger } from "@vygruppen/spor-react";
Props
Name | Type | Required? | Description |
|---|---|---|---|
children | React.ReactNode | Content of triggerButton | |
variant | "core" | "ghost" | "floating" | Defaults to "core" | |
icon | React.ReactNode | Icon to be shown on the left side of trigger |
<MenuContent />
import { MenuContent } from "@vygruppen/spor-react";
Props
Name | Type | Required? | Description |
|---|---|---|---|
children | React.ReactNode | Content of the card | |
maxHeight | string | Set this to create a scrollable menu. |
<MenuItem />
import { MenuItem } from "@vygruppen/spor-react";
Props
Name | Type | Required? | Description |
|---|---|---|---|
children | React.ReactNode | ||
itemCommand | string | Display a command on the right side of the item | |
closeOnSelect | boolean | Whether the menu should be closed when the option is selected. | |
disabled | boolean | ||
leftIcon | React.ReactNode | ||
rightIcon | React.ReactNode |
<MenuTriggerItem />
import { MenuTriggerItem } from "@vygruppen/spor-react";
Props
Name | Type | Required? | Description |
|---|---|---|---|
children | React.ReactNode | ||
leftIcon | React.ReactNode | ||
rightIcon | React.ReactNode |
<MenuRadioItemGroup />
import { MenuRadioItemGroup } from "@vygruppen/spor-react";
Props
Name | Type | Required? | Description |
|---|---|---|---|
children | React.ReactNode | children should be MenuRadioItem's |
<MenuRadioItem />
import { MenuRadioItem } from "@vygruppen/spor-react";
Props
Name | Type | Required? | Description |
|---|---|---|---|
children | React.ReactNode | ||
closeOnSelect | boolean | Whether the menu should be closed when the option is selected. |
<MenuItemGroup />
import { MenuItemGroup } from "@vygruppen/spor-react";
Props
Name | Type | Required? | Description |
|---|---|---|---|
children | React.ReactNode | ||
label | string |
<MenuCheckboxItem />
import { MenuCheckboxItem } from "@vygruppen/spor-react";
Props
Name | Type | Required? | Description |
|---|---|---|---|
children | React.ReactNode | ||
checked | boolean | ||
onCheckedChange | function | (checked: boolean) => void | |
closeOnSelect | boolean | Default false. Whether the menu should be closed when the option is selected. |
<MenuSeparator />
import { MenuSeparator } from "@vygruppen/spor-react";