Menu
A menu is a list of options or commands presented to the user that can be used to perform various operations. Menus are typically presented as a dropdown list, where clicking or hovering over a main menu item reveals the list of options.
import {QMenu} from "@qui/react"
Overview
Our menu component is based on Floating UI, a helper library for creating "floating" elements.
Examples
Showcase
To hide and show the menu, supply an interactive element to the anchor prop. The anchor is used to compute the position of the floating panel. If supplied as an element, event handlers will be applied for triggering the open/close state of the menu on interaction.
It can also be supplied as a function or ref, allowing you to customize based on the state of the panel.
import {ReactNode} from "react"import {FileText, FolderClosed, LayoutDashboard} from "lucide-react"import {QButton, QMenu, QMenuItem} from "@qui/react"export default function Showcase(): ReactNode {const items: QMenuItem[] = [{endIcon: LayoutDashboard,id: "dashboard",label: "Dashboard",},{endIcon: FolderClosed,id: "files",label: "Files",},{endIcon: FileText,id: "docs",label: "Docs",},]return (<div className="flex justify-center gap-6"><QMenuanchor={<QButton aria-label="Default" color="primary" variant="fill">Default</QButton>}items={items}/><QMenuanchor={({open, ...anchorProps}) => (<QButtonaria-label="Customized"color="primary"selected={open}variant="fill"{...anchorProps}>Customized</QButton>)}items={items}/></div>)}
Kitchen Sink
If you intend to render the menu item inline, use the QInlineMenu
component instead. The following is an example of an inline menu with a diverse array of items.
The text content of the menu is configured using the label, description, secondaryText, and sectionTitle properties. Each of these properties are configured with reasonable defaults for font size, line height, and font weight. Should you need to customize these attributes, supply a ReactNode with your own styles.
import {ReactNode} from "react"import {ExternalLink, Link2, Trash} from "lucide-react"import {Link} from "react-router"import {QInlineMenu} from "@qui/react"export default function KitchenSink(): ReactNode {return (<div className="grid justify-center"><QInlineMenuitems={[{id: "start-icon", label: "Start Icon", startIcon: ExternalLink},{endIcon: ExternalLink, id: "end-icon", label: "End Icon"},{description: "Description", id: "text-labels", label: "Label"},{description: "Description",id: "with-secondary-text",label: "Label",secondaryText: "Secondary Text",},{description: "Description",endIcon: Trash,endIconSize: "s",id: "with-end-icon",label: "Label",secondaryText: "Secondary Text",},{disabled: true, id: "disabled", label: "Disabled"},{id: "with-separator-and-title",sectionTitle: "Section Title (with top separator)",separator: "top",},{id: "just the label", label: "Label"},{id: "bottom-separator",label: "Label (with bottom separator)",separator: "bottom",},{endIcon: ExternalLink,id: "google-link",label: "External Link",render: <a href="https://www.google.com" target="_blank" />,},{endIcon: Link2,id: "custom-render",label: "Internal Link",render: <Link to="#item-root-element" />,},]}/></div>)}
Item Root Element
Supply a ReactElement
to the render prop to override the root element of the menu item. This behavior is useful for creating links.
import {ReactNode} from "react"import {ExternalLink, Link2} from "lucide-react"import {Link} from "react-router"import {QInlineMenu} from "@qui/react"export default function CustomMenuItem(): ReactNode {return (<div className="grid justify-center"><QInlineMenuitems={[{endIcon: ExternalLink,id: "external-link",label: "External Link",render: <a href="https://www.google.com" target="_blank" />,},{endIcon: Link2,id: "internal-link",label: "Internal Link (react-router)",render: <Link to="#render" />,},]}/></div>)}
Sub Menus
Supply the items field to any menu item to render a nested menu.
import {ReactNode} from "react"import {ChevronRight,FileText,FolderClosed,LayoutDashboard,} from "lucide-react"import {QButton, QMenu} from "@qui/react"export default function SubMenu(): ReactNode {return (<div className="grid justify-center"><QMenuanchor={<QButton aria-label="Action" color="primary" variant="outline">Action</QButton>}items={[{id: "dashboard",label: "Dashboard",startIcon: LayoutDashboard,},{endIcon: ChevronRight,id: "files",items: [{id: "file-1",label: "File",},{id: "file-2",label: "File",},{endIcon: ChevronRight,id: "folder",items: [{id: "folder-file-1", label: "File"},{id: "folder-file-2", label: "File"},{id: "folder-file-3", label: "File"},],label: "Folder",},],label: "Files",startIcon: FolderClosed,},{id: "docs",label: "Docs",startIcon: FileText,},]}/></div>)}
Anchor as Ref
The anchor can be supplied as a reference to a ReactElement instead. When you do this, the menu's event handlers are not bound, so you'll need to manually control the open state.
import {MouseEvent, ReactNode, useRef, useState} from "react"import {QAvatar, QButton, QMenu} from "@qui/react"export default function AnchorRef(): ReactNode {const anchorRef = useRef(null)const [open, setOpen] = useState(false)return (<div className="flex items-center justify-center gap-6"><QButtoncolor="primary"onClick={(event: MouseEvent) => {/** since the anchor is attached to another element, we must prevent the* click event from bubbling. Otherwise, the list will immediately close* from the mouseup event.*/event.stopPropagation()setOpen((prevState) => !prevState)}}variant="fill">Action</QButton><QAvatar ref={anchorRef} content="AV" variant="text" /><QMenuanchor={anchorRef}items={[{id: "projects",label: "Projects",},{id: "files",label: "Files",},]}onOpenChange={(value: boolean) => {setOpen(value)}}open={open}/></div>)}
API
QMenuItem
Name & Description | Option(s) | Default |
---|---|---|
id * Unique identifier of the item |
| |
Optional description shown below the label. | ReactNode | |
When true, the menu item is disabled |
| false |
icon positioned after the label |
| |
The size of the endIcon. Some icons may not look right at the default size.
Provide this input to fine-tune. |
| |
Nested menu items. | QMenuItem[] | |
The menu item's primary message | ReactNode | |
Item renderer for overriding the default item |
| <div /> |
| 'menuitem' | |
Label rendered opposite to the main label and description. | ReactNode | |
A label that renders above the item's content. Best paired with separator 'top' to visually partition sections of the menu. | ReactNode | |
Draw a separator line (thin border) between this item and other items. |
| |
The size of the menu item and its contents. |
| 'm' |
icon positioned before the label. |
| |
The size of the startIcon. Some icons may not look right at the default size.
Provide this input to fine-tune. |
|
id
*
Type
string
Description
Unique identifier of the item
Type
ReactNode
Description
Optional description shown below the label.
Type
boolean
Default
false
Description
When true, the menu item is disabled
Type
| LucideIcon| ReactNode
Description
icon positioned after the label
Type
| 'xs'| 's'| 'm'| 'l'| 'xl'| string| number
Description
The size of the endIcon. Some icons may not look right at the default size.
Provide this input to fine-tune.
Type
QMenuItem[]
Description
Nested menu items.
Type
ReactElement
Default
<div />
Description
Item renderer for overriding the default item
Type
string
Default
'menuitem'
Description
HTML role
attribute applied to the menuitem element. Use this property to override the
role of the menuitem.
Type
ReactNode
Description
Label rendered opposite to the main label and description.
Type
| 'top'| 'bottom'| 'both'
Description
Draw a separator line (thin border) between this item and other items.
Type
's' | 'm'
Default
'm'
Description
The size of the menu item and its contents.
Type
| LucideIcon| ReactNode
Description
icon positioned before the label.
Type
| 'xs'| 's'| 'm'| 'l'| 'xl'| string| number
Description
The size of the startIcon. Some icons may not look right at the default size.
Provide this input to fine-tune.
QMenu
Name & Description | Option(s) | Default |
---|---|---|
The interactive element that will be used to compute the position of the
floating panel. If supplied as an element, event handlers will be applied for
triggering the open/close state of the menu on interaction. Can also be
supplied as a function that returns an element, or a reference to a
ReactElement. |
| |
Menu item array. | QMenuItem[] | |
The CSS transition-duration of the enter and exit animations. Supply as a
number to configure both transitions at once, or supply an object to configure
the enter and exit transitions independently. |
| 250 |
Configure the element shown when arrow is true . |
| |
The component used for the root node. It can be a React component or element. |
| 'div' |
If true, the menu's first item will automatically gain focus when the
component is opened. This is recommended for optimal accessibility. |
| true |
Ensure that the component remains anchored to its reference element following
screen resizes or position changes. |
| |
The className property of the Element
interface gets and sets the value of the
class attribute
of the specified element. |
| |
The default value when uncontrolled. |
| |
The default selected menu item index. |
| |
If true, the component is disabled. |
| |
Box shadow severity of the panel, based on the five elevation styles provided
by QDS. A higher number means a more severe box shadow. Supply 0 to disable
the box shadow. |
| |
Whether to flip the component's placement to keep it in view. |
| true |
| false | |
| false | |
The controlled id of the component. If not provided, a value will be used as
a fallback. |
| |
Determines whether focus should loop around when navigating past the first
or last item. This creates a continuous cycle through the menu items using
arrow keys. |
| true |
The distance between the component and its anchor element. |
| 0 |
Callback fired when the active menu item changes.
|
| |
Callback fired when panel visibility changes.
|
| |
The controlled state for the menu. Supplying this value will override
hover and focus events. |
| |
Describes the placement of the component before FloatingUI has applied all the
modifiers that may have flipped or altered the component. The final placement
may differ from this input property. |
| 'top' |
CSS position attribute of the component. Can be "absolute" or "fixed". |
| 'absolute' |
If true, focus will be restored to the component's anchor element on close. |
| true |
| 'menu' | |
Applies a default size to each menu item in this menu. Note that each menu
item's size, if configured, will override this value. |
| 'm' |
The style global attribute
contains CSS styling
declarations to be applied to the element. | CSSProperties | |
| 1000 |
Type
| Element| ((props: Props,) => Element)| RefObject<HTMLElement | object>
Description
The interactive element that will be used to compute the position of the
floating panel. If supplied as an element, event handlers will be applied for
triggering the open/close state of the menu on interaction. Can also be
supplied as a function that returns an element, or a reference to a
ReactElement.
Related symbols
Type
QMenuItem[]
Description
Menu item array.
Type
| number| {enter: numberexit: number}
Default
250
Description
The CSS transition-duration of the enter and exit animations. Supply as a
number to configure both transitions at once, or supply an object to configure
the enter and exit transitions independently.
Type
{className?: stringfill?: stringheight?: numberstyle?: CSSPropertieswidth?: number}
Description
Configure the element shown when arrow is
true
.Type
| ElementType| ComponentType
Default
'div'
Description
The component used for the root node. It can be a React component or element.
Type
boolean
Default
true
Description
If true, the menu's first item will automatically gain focus when the
component is opened. This is recommended for optimal accessibility.
Type
boolean
Description
Ensure that the component remains anchored to its reference element following
screen resizes or position changes.
Type
string
Description
The className property of the Element
interface gets and sets the value of the
class attribute
of the specified element.
Type
boolean
Description
The default value when uncontrolled.
Type
number
Description
The default selected menu item index.
Type
boolean
Description
If true, the component is disabled.
Type
| 0| 1| 2| 3| 4| 5| '0'| '1'| '2'| '3'| '4'| '5'
Description
Box shadow severity of the panel, based on the five elevation styles provided
by QDS. A higher number means a more severe box shadow. Supply 0 to disable
the box shadow.
Type
boolean
Default
true
Description
Whether to flip the component's placement to keep it in view.
Type
boolean
Default
false
Description
If true, the component will show when the anchor element is focused.
This property is ignored if open is supplied.
Type
boolean
Default
false
Description
If true, the component will show when the anchor element is hovered. This
property is ignored if open is supplied.
Type
string
Description
The controlled id of the component. If not provided, a value will be used as
a fallback.
Type
boolean
Default
true
Description
Determines whether focus should loop around when navigating past the first
or last item. This creates a continuous cycle through the menu items using
arrow keys.
Type
| number| {alignmentAxis?: numbercrossAxis?: numbermainAxis?: number}
Default
0
Description
The distance between the component and its anchor element.
Type
(index: number,) => void
Description
Callback fired when the active menu item changes.
- index{number}
Type
(open: boolean,event?: Event,reason?:| 'ancestor-scroll'| 'click'| 'escape-key'| 'focus'| 'hover'| 'list-navigation'| 'outside-press'| 'reference-press'| 'safe-polygon',) => void
Description
Callback fired when panel visibility changes.
- openThe updated state.
- eventThe event that triggered the change.
- reasonThe cause of the change.
Type
boolean
Description
The controlled state for the menu. Supplying this value will override
hover and focus events.
Type
| 'top-start'| 'top'| 'top-end'| 'bottom-start'| 'bottom'| 'bottom-end'| 'left-start'| 'left'| 'left-end'| 'right-start'| 'right'| 'right-end'
Default
'top'
Description
Describes the placement of the component before FloatingUI has applied all the
modifiers that may have flipped or altered the component. The final placement
may differ from this input property.
Type
| 'absolute'| 'fixed'
Default
'absolute'
Description
CSS position attribute of the component. Can be "absolute" or "fixed".
Type
boolean
Default
true
Description
If true, focus will be restored to the component's anchor element on close.
Type
string
Default
'menu'
Description
HTML role
attribute applied to the element that wraps the menu items.
Type
's' | 'm'
Default
'm'
Description
Applies a default size to each menu item in this menu. Note that each menu
item's size, if configured, will override this value.
Type
CSSProperties
Description
The style global attribute
contains CSS styling
declarations to be applied to the element.