Skip to content
Vy logo
  • Identitet
  • Spor
  • Resources
Components

Menu

A menu can be used to create an accessible dropdown menu.

FigmaGitHub

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 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
childrenReact.ReactNodeChildren should contain CardSelectTrigger and CardSelectContent
openboolean
onOpenChange(details: OpenChangeDetails) => void
positioningPositioningOptions Decides the placement of the menu. Example: {{ placement: "right-start" }}

<MenuTrigger />

import { MenuTrigger } from "@vygruppen/spor-react";

Props

Name
Type
Required?
Description
childrenReact.ReactNodeContent of triggerButton
variant"core" | "ghost" | "floating"Defaults to "core"
iconReact.ReactNodeIcon to be shown on the left side of trigger

<MenuContent />

import { MenuContent } from "@vygruppen/spor-react";

Props

Name
Type
Required?
Description
childrenReact.ReactNodeContent of the card
maxHeightstringSet this to create a scrollable menu.

<MenuItem />

import { MenuItem } from "@vygruppen/spor-react";

Props

Name
Type
Required?
Description
childrenReact.ReactNode
itemCommandstringDisplay a command on the right side of the item
closeOnSelectbooleanWhether the menu should be closed when the option is selected.
disabledboolean
leftIconReact.ReactNode
rightIconReact.ReactNode

<MenuTriggerItem />

import { MenuTriggerItem } from "@vygruppen/spor-react";

Props

Name
Type
Required?
Description
childrenReact.ReactNode
leftIconReact.ReactNode
rightIconReact.ReactNode

<MenuRadioItemGroup />

import { MenuRadioItemGroup } from "@vygruppen/spor-react";

Props

Name
Type
Required?
Description
childrenReact.ReactNodechildren should be MenuRadioItem's

<MenuRadioItem />

import { MenuRadioItem } from "@vygruppen/spor-react";

Props

Name
Type
Required?
Description
childrenReact.ReactNode
closeOnSelectbooleanWhether the menu should be closed when the option is selected.

<MenuItemGroup />

import { MenuItemGroup } from "@vygruppen/spor-react";

Props

Name
Type
Required?
Description
childrenReact.ReactNode
labelstring

<MenuCheckboxItem />

import { MenuCheckboxItem } from "@vygruppen/spor-react";

Props

Name
Type
Required?
Description
childrenReact.ReactNode
checkedboolean
onCheckedChangefunction(checked: boolean) => void
closeOnSelectbooleanDefault false. Whether the menu should be closed when the option is selected.

<MenuSeparator />

import { MenuSeparator } from "@vygruppen/spor-react";