PatternFly

Menu

Examples

Basic menus

A menu may contain multiple variations of <MenuItem> components. The following example shows a few different states of menu items, where they may:

  • Use the itemId property to link to callbacks. In this example, the onSelect property logs information to the console when a menu item is selected. In practice, specific actions can be linked to onSelect callbacks.
  • Use the to property to direct users to other resources or webpages after selecting a menu item, and the onClick property to pass in a callback for specific menu items.
  • Use the isDisabled property to disable a menu item.
  • Use the isPlain property to remove the outer box shadow and style the menu plainly instead.

Danger menu item

To indicate that a <MenuItem> is connected to a potentially destructive action, use the isDanger property. The "Delete" item in the following example demonstrates how danger items look.

With icons

Use the icon property to add a familiar icon before a <MenuItem> to accelerate text label recognition.

With actions

To connect a menu item to an action icon, add a <MenuItemAction> to a <MenuItem>, and use the icon property to load an easily recognizable icon.

To trigger an action when any menu action icon is selected, pass a callback to the onActionClick property of the <Menu>. The following example logs to the console any time any action icon is selected.

To trigger an action when a specific item's action icon is selected, pass in the onClick property to that <MenuItemAction>. The following example logs "clicked on code icon" to the console when the "code" icon is selected.

Actions

Use the to property to add a link to a <MenuItem> that directs users to a new page when the item is selected. Use the isExternalLink property when linking to external resources. This will annotate a menu item link with an external link icon when they navigate to the link or hover over it, as well as add target="_blank" so that the link opens in a new tab or window.

With descriptions

Use the description property to add short descriptive text below any menu item that needs additional context.

Item checkbox

Use the hasCheck property to add a checkbox to a <MenuItem>. Use the isSelected property to indicate when a <MenuItem> is selected.

Add a <MenuFooter> that contains separate, but related actions at the bottom of a menu.

Separated items

Use a divider to visually separate <MenuContent>. Use the component property to specify the type of divider component to use.

Titled groups of items

Add a <MenuGroup> to organize <MenuContent> and use the label property to title a group of menu items. Use the labelHeadingLevel property to assign a heading level to the menu group label.

With favorites

The following menu example allows users to favorite menu items, an action that duplicates a menu item and places it in a separate group at the top of the menu. The isFavorited property identifies items that a user has favorited.

All actions

Filtering with search input

A search input component can be placed within <MenuSearch> and <MenuSearchInput> to render a search input at the top of the menu. In the following example, the onChange property of the text input is passed a callback that filters menu items as a user types.


Option single select menu

The following example demonstrates a single option select menu that persists a selected menu item. Use the selected property on the <Menu> to label a selected item with a checkmark. You can also use the isSelected property on a <MenuItem> to indicate that it is selected.

You must also use the role property on the <Menu> with a value of "listbox" when using a non-checkbox select menu.

Option multi select menu

To persist multiple selections that a user makes, use a multiple option select menu. To enable multi select, pass an array containing each selected itemId to the selected property on the <Menu>, and pass the isAriaMultiselectable property on the <MenuList>.

Similar to a single select menu, you must also pass role="listbox" to the <Menu>.

Scrollable menus

Use the isScrollable property to make a long <Menu> scrollable and visually condensed.

Scrollable menu with custom height

Adjust the visual size of a scrollable menu by using the menuHeight property within <MenuContent>. This example adjusts the height to 200px.

With view more

If you want to initially render only a certain number of menu items within a large menu, you can add a "view more" menu item with a callback passed into its onClick property that will render additional menu items.

In this example, 3 additional menu items are revealed each time the "view more" option is selected, with a loading icon simulating a network call to fetch more items. After all items are visible, the "view more" link disappears.

With drilldown

Use a drilldown menu to contain different levels of menu items. When a parent menu item (an item that has a submenu of children) is selected, the menu is replaced with the children items.

  • To indicate that a menu contains a drilldown, use the containsDrilldown property.
  • To indicate the path of drilled-in menu item ids, use the drilldownItemPath property.
  • Pass in an array of drilled-in menus with the drilledInMenus property.
  • Use the onDrillIn and onDrillOut properties to contain callbacks for drilling into and drilling out of a submenu, respectively.
  • To account for updated heights as menus drill in and out of use, use the onGetMenuHeight property. When starting from a drilled-in state, the onGetMenuHeight property must define the height of the root menu.

Initially drilled-in menu

To render an initially drilled-in menu, the drilldownItemPath, drilledInMenus, and activeMenu properties must be set to default values.

With drilldown - submenu functions

For added flexibility with large menus, you may create a menu by passing a function to drilldownMenu. This approach allows you to create menu items dynamically, rather than creating everything up front.

With drilldown breadcrumbs

Use breadcrumbs when a drilldown menu has more than 2 levels to offer users better navigation.

To control the height of a menu, use the maxMenuHeight property. Selecting the "Set max menu height" checkbox in the following example sets the menu height to "100px" and makes the menu scrollable.


With drilldown and inline filter

Props

*required
NameTypeDefaultDescription
*required
NameTypeDefaultDescription
*required
NameTypeDefaultDescription
*required
NameTypeDefaultDescription
aria-labelrequiredstringAccessibility label
actionIdanyIdentifies the action item in the onActionClick on the Menu
classNamestringAdditional classes added to the action button
icon'favorites' | React.ReactNodeThe action icon to use
isDisabledbooleanDisables action, can also be specified on the MenuItem instead
isFavoritedbooleanFlag indicating if the item is favorited
onClick(event?: any) => voidCallback on action click, can also specify onActionClick on the Menu instead
*required
NameTypeDefaultDescription
*required
NameTypeDefaultDescription
childrenReact.ReactNodeItems within search
*required
NameTypeDefaultDescription
childrenReact.ReactNodeItems within input
*required
NameTypeDefaultDescription
Container that links a menu and menu toggle together, to handle basic keyboard input and control the opening and closing of a menu. This component is currently in beta and is subject to change.
*required
NameTypeDefaultDescription
isOpenrequiredbooleanFlag to indicate if menu is opened.
menurequiredReact.ReactElement<any, string | React.JSXElementConstructor<any>>Menu to be rendered
menuRefrequiredReact.RefObject<any>Reference to the menu
togglerequiredReact.ReactNodeToggle to be rendered
toggleRefrequiredReact.RefObject<any>Reference to the toggle
onOpenChange(isOpen: boolean) => voidCallback to change the open state of the menu. Triggered by clicking outside of the menu, or by pressing any keys specificed in onOpenChangeKeys.
onOpenChangeKeysstring[]['Escape', 'Tab']Keys that trigger onOpenChange, defaults to tab and escape. It is highly recommended to include Escape in the array, while Tab may be omitted if the menu contains non-menu items that are focusable.
popperPropsMenuPopperPropsAdditional properties to pass to the Popper
zIndexnumber9999z-index of the dropdown menu
*required
NameTypeDefaultDescription
direction'up' | 'down'Vertical direction of the popper. If enableFlip is set to true, this will set the initial direction before the popper flips.
enableFlipbooleanEnable to flip the popper when it reaches the boundary
maxWidthstring | 'trigger'Maximum width of the popper. If the value is "trigger", it will set the max width to the dropdown toggle's width
minWidthstring | 'trigger'Minimum width of the popper. If the value is "trigger", it will set the min width to the dropdown toggle's width
position'right' | 'left' | 'center' | 'start' | 'end'Horizontal position of the popper
preventOverflowbooleanFlag to prevent the popper from overflowing its container and becoming partially obscured.
widthstring | 'trigger'Custom width of the popper. If the value is "trigger", it will set the width to the dropdown toggle's width

TooltipProps

*required
NameTypeDefaultDescription
contentrequiredReact.ReactNodeTooltip content
animationDurationnumberCSS fade transition animation duration
appendToHTMLElement | ((ref?: HTMLElement) => HTMLElement)The element to append the tooltip to, defaults to body
aria'describedby' | 'labelledby' | 'none'aria-labelledby or aria-describedby for tooltip. The trigger will be cloned to add the aria attribute, and the corresponding id in the form of 'pf-tooltip-#' is added to the content container. If you don't want that or prefer to add the aria attribute yourself on the trigger, set aria to 'none'.
childrenReactElement<any>The trigger reference element to which the Tooltip is relatively placed to. If you cannot wrap the element with the Tooltip, you can use the triggerRef prop instead. Usage: <Tooltip><Button>Reference</Button></Tooltip>
classNamestringTooltip additional class
distancenumberDistance of the tooltip to its target, defaults to 15
enableFlipbooleanIf true, tries to keep the tooltip in view by flipping it if necessary
entryDelaynumberDelay in ms before the tooltip appears
exitDelaynumberDelay in ms before the tooltip disappears, Avoid passing in a value of "0", as users should be given ample time to move their mouse from the trigger to the tooltip content without the content being hidden.
flipBehavior| 'flip' | ( | 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-start' | 'left-end' | 'right-start' | 'right-end' )[]The desired position to flip the tooltip to if the initial position is not possible. By setting this prop to 'flip' it attempts to flip the tooltip to the opposite side if there is no space. You can also pass an array of positions that determines the flip order. It should contain the initial position followed by alternative positions if that position is unavailable. Example: Initial position is 'top'. Button with tooltip is in the top right corner. 'flipBehavior' is set to ['top', 'right', 'left']. Since there is no space to the top, it checks if right is available. There's also no space to the right, so it finally shows the tooltip on the left.
idstringid of the tooltip
isContentLeftAlignedbooleanFlag to indicate that the text content is left aligned
isVisiblebooleanvalue for visibility when trigger is 'manual'
maxWidthstringMaximum width of the tooltip (default 18.75rem)
minWidthstring | 'trigger'Minimum width of the tooltip. If set to "trigger", the minimum width will be set to the reference element width.
onTooltipHidden() => voidCallback when tooltip's hide transition has finished executing
position| TooltipPosition | 'auto' | 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-start' | 'left-end' | 'right-start' | 'right-end'Tooltip position. Note: With 'enableFlip' set to true, it will change the position if there is not enough space for the starting position. The behavior of where it flips to can be controlled through the flipBehavior prop. The 'auto' position chooses the side with the most space. The 'auto' position requires the 'enableFlip' prop to be true.
triggerstringTooltip trigger: click, mouseenter, focus, manual Set to manual to trigger tooltip programmatically (through the isVisible prop)
triggerRefHTMLElement | (() => HTMLElement) | React.RefObject<any>The trigger reference element to which the Tooltip is relatively placed to. If you can wrap the element with the Tooltip, you can use the children prop instead, or both props together. When passed along with the trigger prop, the div element that wraps the trigger will be removed. Usage: <Tooltip triggerRef={() => document.getElementById('reference-element')} />
Unknown'off' | 'polite'Determines whether the tooltip is an aria-live region. If the triggerRef prop is passed in the default behavior is 'polite' in order to ensure the tooltip contents is announced to assistive technologies. Otherwise the default behavior is 'off'.
zIndexnumberz-index of the tooltip

CSS variables

SelectorVariableValue
.pf-v5-c-menu--pf-v5-global--Color--100
#151515
.pf-v5-c-menu--pf-v5-global--Color--200
#6a6e73
.pf-v5-c-menu--pf-v5-global--BorderColor--100
#d2d2d2
.pf-v5-c-menu--pf-v5-global--primary-color--100
#06c
.pf-v5-c-menu--pf-v5-global--link--Color
#06c
.pf-v5-c-menu--pf-v5-global--link--Color--hover
#004080
.pf-v5-c-menu--pf-v5-global--BackgroundColor--100
#fff
.pf-v5-c-menu--pf-v5-global--icon--Color--light
#6a6e73
.pf-v5-c-menu--pf-v5-global--icon--Color--dark
#151515
.pf-v5-c-menu--pf-v5-c-menu--BackgroundColor
#fff
.pf-v5-c-menu--pf-v5-c-menu--BoxShadow
0 0.25rem 0.5rem 0rem rgba(3, 3, 3, 0.12), 0 0 0.25rem 0 rgba(3, 3, 3, 0.06)
.pf-v5-c-menu--pf-v5-c-menu--MinWidth
auto
.pf-v5-c-menu--pf-v5-c-menu--Width
auto
.pf-v5-c-menu--pf-v5-c-menu--ZIndex
200
.pf-v5-c-menu--pf-v5-c-menu--Top
auto
.pf-v5-c-menu--pf-v5-c-menu--m-flyout__menu--Top
calc(0.5rem * -1 + 0px)
.pf-v5-c-menu--pf-v5-c-menu--m-flyout__menu--Right
auto
.pf-v5-c-menu--pf-v5-c-menu--m-flyout__menu--Bottom
auto
.pf-v5-c-menu--pf-v5-c-menu--m-flyout__menu--Left
calc(100% + 0px)
.pf-v5-c-menu--pf-v5-c-menu--m-flyout__menu--m-top--Bottom
calc(0.5rem * -1)
.pf-v5-c-menu--pf-v5-c-menu--m-flyout__menu--m-left--Right
calc(100% + 0px)
.pf-v5-c-menu--pf-v5-c-menu--m-plain--BoxShadow
none
.pf-v5-c-menu--pf-v5-c-menu--m-flyout__menu--top-offset
0px
.pf-v5-c-menu--pf-v5-c-menu--m-flyout__menu--left-offset
0px
.pf-v5-c-menu--pf-v5-c-menu--m-flyout__menu--m-left--right-offset
0px
.pf-v5-c-menu--pf-v5-c-menu__content--Height
auto
.pf-v5-c-menu--pf-v5-c-menu__content--MaxHeight
none
.pf-v5-c-menu--pf-v5-c-menu--m-scrollable__content--MaxHeight
18.75rem
.pf-v5-c-menu--pf-v5-c-menu--c-divider--MarginTop
0
.pf-v5-c-menu--pf-v5-c-menu--c-divider--MarginBottom
0
.pf-v5-c-menu--pf-v5-c-menu__list--c-divider--MarginTop
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__list--c-divider--MarginBottom
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__header--PaddingTop
1rem
.pf-v5-c-menu--pf-v5-c-menu__header--PaddingRight
1rem
.pf-v5-c-menu--pf-v5-c-menu__header--PaddingBottom
1rem
.pf-v5-c-menu--pf-v5-c-menu__header--PaddingLeft
1rem
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--MarginTop
calc(1rem * -1 / 2)
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--MarginRight
calc(1rem * -1 / 2)
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--MarginBottom
calc(1rem * -1 / 2)
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--MarginLeft
calc(1rem * -1 / 2)
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--PaddingTop
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--PaddingRight
1rem
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--PaddingBottom
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--PaddingLeft
1rem
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--BackgroundColor
transparent
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--hover--BackgroundColor
#f0f0f0
.pf-v5-c-menu--pf-v5-c-menu__header--c-menu__item--focus--BackgroundColor
#f0f0f0
.pf-v5-c-menu--pf-v5-c-menu__search--PaddingTop
1rem
.pf-v5-c-menu--pf-v5-c-menu__search--PaddingRight
1rem
.pf-v5-c-menu--pf-v5-c-menu__search--PaddingBottom
1rem
.pf-v5-c-menu--pf-v5-c-menu__search--PaddingLeft
1rem
.pf-v5-c-menu--pf-v5-c-menu__header__search--PaddingTop
0
.pf-v5-c-menu--pf-v5-c-menu__list--Display
block
.pf-v5-c-menu--pf-v5-c-menu__list--PaddingTop
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__list--PaddingBottom
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__list-item--Display
flex
.pf-v5-c-menu--pf-v5-c-menu__list-item--Color
#151515
.pf-v5-c-menu--pf-v5-c-menu__list-item--BackgroundColor
transparent
.pf-v5-c-menu--pf-v5-c-menu__list-item--hover--BackgroundColor
#f0f0f0
.pf-v5-c-menu--pf-v5-c-menu__list-item--focus-within--BackgroundColor
#f0f0f0
.pf-v5-c-menu--pf-v5-c-menu__list-item--m-loading--PaddingTop
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item--PaddingTop
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item--PaddingRight
1rem
.pf-v5-c-menu--pf-v5-c-menu__item--PaddingBottom
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item--PaddingLeft
1rem
.pf-v5-c-menu--pf-v5-c-menu__item--OutlineOffset
calc(0.125rem * -1)
.pf-v5-c-menu--pf-v5-c-menu__item--FontSize
1rem
.pf-v5-c-menu--pf-v5-c-menu__item--FontWeight
400
.pf-v5-c-menu--pf-v5-c-menu__item--LineHeight
1.5
.pf-v5-c-menu--pf-v5-c-menu__list-item--m-disabled__item--Color
#6a6e73
.pf-v5-c-menu--pf-v5-c-menu__list-item--m-danger__item--Color
#c9190b
.pf-v5-c-menu--pf-v5-c-menu__list-item--m-load__item--Color
#06c
.pf-v5-c-menu--pf-v5-c-menu__group--Display
block
.pf-v5-c-menu--pf-v5-c-menu__group-title--PaddingTop
1rem
.pf-v5-c-menu--pf-v5-c-menu__group-title--PaddingRight
1rem
.pf-v5-c-menu--pf-v5-c-menu__group-title--PaddingLeft
1rem
.pf-v5-c-menu--pf-v5-c-menu__group-title--FontSize
0.75rem
.pf-v5-c-menu--pf-v5-c-menu__group-title--FontWeight
400
.pf-v5-c-menu--pf-v5-c-menu__group-title--Color
#6a6e73
.pf-v5-c-menu--pf-v5-c-menu__item-description--FontSize
0.75rem
.pf-v5-c-menu--pf-v5-c-menu__item-description--Color
#6a6e73
.pf-v5-c-menu--pf-v5-c-menu__item-icon--MarginRight
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item-check--MarginRight
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item-toggle-icon--PaddingRight
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item-toggle-icon--PaddingLeft
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__list-item--m-disabled__item-toggle-icon--Color
#d2d2d2
.pf-v5-c-menu--pf-v5-c-menu__item-text--item-toggle-icon--MarginLeft
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item-toggle-icon--item-text--MarginLeft
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item-select-icon--MarginLeft
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item-select-icon--Color
#06c
.pf-v5-c-menu--pf-v5-c-menu__item-select-icon--FontSize
0.75rem
.pf-v5-c-menu--pf-v5-c-menu__item-external-icon--MarginLeft
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item-external-icon--Color
#06c
.pf-v5-c-menu--pf-v5-c-menu__item-external-icon--FontSize
0.75rem
.pf-v5-c-menu--pf-v5-c-menu__item-external-icon--Opacity
0
.pf-v5-c-menu--pf-v5-c-menu__item-action--PaddingTop
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item-action--PaddingRight
1rem
.pf-v5-c-menu--pf-v5-c-menu__item-action--PaddingBottom
0.5rem
.pf-v5-c-menu--pf-v5-c-menu__item-action--PaddingLeft
1rem
.pf-v5-c-menu--pf-v5-c-menu__item-action--Color
#6a6e73
.pf-v5-c-menu--pf-v5-c-menu__item-action--BackgroundColor
transparent
.pf-v5-c-menu--pf-v5-c-menu__item-action--hover--Color
#151515
.pf-v5-c-menu--pf-v5-c-menu__item-action--disabled--Color
#d2d2d2
.pf-v5-c-menu--pf-v5-c-menu__item-action--m-favorited--Color
#f0ab00
.pf-v5-c-menu--pf-v5-c-menu__item-action--m-favorited--hover--Color
#c58c00
.pf-v5-c-menu--pf-v5-c-menu__item-action-icon--Height
calc(1rem * 1.5)
.pf-v5-c-menu--pf-v5-c-menu__item-action--m-favorite__icon--FontSize
0.75rem
.pf-v5-c-menu--pf-v5-c-menu__breadcrumb--PaddingTop
1rem
.pf-v5-c-menu--pf-v5-c-menu__breadcrumb--PaddingRight
1rem
.pf-v5-c-menu--pf-v5-c-menu__breadcrumb--PaddingBottom
1rem
.pf-v5-c-menu--pf-v5-c-menu__breadcrumb--PaddingLeft
1rem
.pf-v5-c-menu--pf-v5-c-menu__breadcrumb--c-breadcrumb__item--FontSize
1rem
.pf-v5-c-menu--pf-v5-c-menu__breadcrumb--c-breadcrumb__heading--FontSize
1rem
.pf-v5-c-menu--pf-v5-c-menu--m-drilldown--c-menu--Top
0
.pf-v5-c-menu--pf-v5-c-menu--m-drilldown--c-menu--TransitionDuration--transform
250ms
.pf-v5-c-menu--pf-v5-c-menu--m-drilldown--c-menu--Transition
transform 250ms
.pf-v5-c-menu--pf-v5-c-menu--m-drilldown__content--TransitionDuration--height
250ms
.pf-v5-c-menu--pf-v5-c-menu--m-drilldown__content--TransitionDuration--transform
250ms
.pf-v5-c-menu--pf-v5-c-menu--m-drilldown__content--Transition
transform 250ms, height 250ms
.pf-v5-c-menu--pf-v5-c-menu--m-drilldown__list--TransitionDuration--transform
250ms
.pf-v5-c-menu--pf-v5-c-menu--m-drilldown__list--Transition
transform 250ms
.pf-v5-c-menu--pf-v5-c-menu--m-drilled-in--c-menu__list-item--m-current-path--c-menu--ZIndex
100
.pf-v5-c-menu--pf-v5-c-menu__footer--PaddingTop
1rem
.pf-v5-c-menu--pf-v5-c-menu__footer--PaddingRight
1rem
.pf-v5-c-menu--pf-v5-c-menu__footer--PaddingBottom
1rem
.pf-v5-c-menu--pf-v5-c-menu__footer--PaddingLeft
1rem
.pf-v5-c-menu--pf-v5-c-menu__footer--BoxShadow
none
.pf-v5-c-menu--pf-v5-c-menu__footer--after--BorderTopWidth
1px
.pf-v5-c-menu--pf-v5-c-menu__footer--after--BorderTopColor
#d2d2d2
.pf-v5-c-menu--pf-v5-c-menu--m-scrollable__footer--BoxShadow
0 -0.125rem 0.25rem -0.0625rem rgba(3, 3, 3, 0.16)
.pf-v5-c-menu--pf-v5-c-menu--m-scrollable__footer--after--BorderTopWidth
0
.pf-v5-c-menu--pf-v5-c-menu--m-scrollable__footer--after--BorderBottomWidth
1px
.pf-v5-c-menu--pf-v5-c-menu--m-nav--BoxShadow
0 0.5rem 1rem 0 rgba(3, 3, 3, 0.16), 0 0 0.375rem 0 rgba(3, 3, 3, 0.08)