Menu

The Menu component provides dropdown navigation and action lists with support for icons, submenus, and various interaction patterns for organizing application functions.

Usage

import { Menu, MenuAlignment, MenuSide, MenuItemV2Variant, MenuItemV2ActionType, } from 'blend-v1' import { Button, ButtonType } from 'blend-v1' import { Settings, User, LogOut, ChevronDown } from 'lucide-react' function MyComponent() { const menuItems = [ { label: 'Profile', slot1: <User size={16} />, onClick: () => console.log('Profile clicked'), }, { label: 'Settings', slot1: <Settings size={16} />, onClick: () => console.log('Settings clicked'), }, { label: 'Logout', slot1: <LogOut size={16} />, variant: MenuItemV2Variant.ACTION, actionType: MenuItemV2ActionType.DANGER, onClick: () => console.log('Logout clicked'), }, ] return ( <Menu trigger={ <Button text="Open Menu" buttonType={ButtonType.SECONDARY} trailingIcon={<ChevronDown size={16} />} /> } items={[{ items: menuItems }]} alignment={MenuAlignment.CENTER} side={MenuSide.BOTTOM} /> ) }

API Reference

Prop NameType
trigger
React.ReactNode
items
MenuV2GroupType[]
maxHeight
number
minHeight
number
maxWidth
number
minWidth
number
enableSearch
boolean
searchPlaceholder
string
open
boolean
onOpenChange
(open: boolean) => void
asModal
boolean
alignment
MenuAlignment
side
MenuSide
sideOffset
number
alignOffset
number
collisonBoundaryRef
Element | null | Array<Element | null>
Prop NameType
label
string
subLabel
string
slot1
React.ReactNode
slot2
React.ReactNode
slot3
React.ReactNode
slot4
React.ReactNode
variant
MenuItemV2Variant
actionType
MenuItemV2ActionType
disabled
boolean
onClick
() => void
subMenu
MenuItemV2Type[]

Features

  • Dropdown menu with customizable positioning
  • Support for menu groups with labels and separators
  • Icon support with multiple slot positions
  • Sub-menu support for nested navigation
  • Search functionality for filtering menu items
  • Action variants with primary and danger types
  • Disabled state support
  • Keyboard navigation and accessibility
  • Customizable dimensions and styling
  • Modal and non-modal rendering modes

Usage Examples

Basic Menu

Simple menu with basic items

const menuItems = [ { label: 'Profile', onClick: () => console.log('Profile clicked'), }, { label: 'Settings', onClick: () => console.log('Settings clicked'), }, ] ;<Menu trigger={<Button text="Open Menu" buttonType={ButtonType.SECONDARY} />} items={[{ items: menuItems }]} />

Menu items with leading icons

const menuItems = [ { label: 'Profile', slot1: <User size={16} />, onClick: () => console.log('Profile clicked'), }, { label: 'Settings', slot1: <Settings size={16} />, onClick: () => console.log('Settings clicked'), }, ] ;<Menu trigger={<Button text="Open Menu" buttonType={ButtonType.SECONDARY} />} items={[{ items: menuItems }]} />

Menu organized into groups with labels

const menuGroups = [ { label: 'Account', items: [ { label: 'Profile', slot1: <User size={16} /> }, { label: 'Settings', slot1: <Settings size={16} /> }, ], }, { label: 'Actions', items: [ { label: 'Logout', slot1: <LogOut size={16} />, variant: MenuItemV2Variant.ACTION, actionType: MenuItemV2ActionType.DANGER, }, ], showSeparator: true, }, ] ;<Menu trigger={<Button text="Open Menu" buttonType={ButtonType.SECONDARY} />} items={menuGroups} />

Menu with search functionality

<Menu trigger={<Button text="Search Menu" buttonType={ButtonType.SECONDARY} />} items={[{ items: menuItems }]} enableSearch={true} searchPlaceholder="Search options..." />

Menu with nested sub-menus

const menuItems = [ { label: 'More Options', slot1: <Settings size={16} />, subMenu: [ { label: 'Edit', slot1: <Edit size={16} /> }, { label: 'Delete', slot1: <Trash size={16} />, variant: MenuItemV2Variant.ACTION, actionType: MenuItemV2ActionType.DANGER, }, ], }, ] ;<Menu trigger={<Button text="Sub Menu" buttonType={ButtonType.SECONDARY} />} items={[{ items: menuItems }]} />

Component Tokens

You can style the menu component using the following tokens:

export type MenuItemStates = | 'default' | 'hover' | 'active' | 'focus' | 'focusVisible' | 'disabled' export type MenuTokensType = { shadow: CSSObject['boxShadow'] backgroundColor: CSSObject['backgroundColor'] paddingTop: CSSObject['paddingTop'] paddingBottom: CSSObject['paddingBottom'] border: CSSObject['border'] outline: CSSObject['outline'] borderRadius: CSSObject['borderRadius'] item: { padding: CSSObject['padding'] margin: CSSObject['margin'] borderRadius: CSSObject['borderRadius'] backgroundColor: { [MenuItemV2Variant.DEFAULT]: { enabled: { [key in MenuItemStates]: CSSObject['backgroundColor'] } disabled: { [key in MenuItemStates]: CSSObject['backgroundColor'] } } [MenuItemV2Variant.ACTION]: { [key in MenuItemV2ActionType]: { enabled: { [key in MenuItemStates]: CSSObject['backgroundColor'] } disabled: { [key in MenuItemStates]: CSSObject['backgroundColor'] } } } } cursor: CSSObject['cursor'] gap: CSSObject['gap'] label: { fontSize: CSSObject['fontSize'] fontWeight: CSSObject['fontWeight'] color: { [MenuItemV2Variant.DEFAULT]: { enabled: { [key in MenuItemStates]: CSSObject['color'] } disabled: { [key in MenuItemStates]: CSSObject['color'] } } [MenuItemV2Variant.ACTION]: { [key in MenuItemV2ActionType]: { enabled: { [key in MenuItemStates]: CSSObject['color'] } disabled: { [key in MenuItemStates]: CSSObject['color'] } } } } } subLabel: { fontSize: CSSObject['fontSize'] fontWeight: CSSObject['fontWeight'] color: { [MenuItemV2Variant.DEFAULT]: { enabled: { [key in MenuItemStates]: CSSObject['color'] } disabled: { [key in MenuItemStates]: CSSObject['color'] } } [MenuItemV2Variant.ACTION]: { [key in MenuItemV2ActionType]: { enabled: { [key in MenuItemStates]: CSSObject['color'] } disabled: { [key in MenuItemStates]: CSSObject['color'] } } } } } } seperator: { color: CSSObject['color'] height: CSSObject['height'] margin: CSSObject['margin'] } }