MenusReact
A collection of links and menus for website navigation.
Rendered by React 19.3.1
Loading React…Installation
npm i @hamur/reactNot on npm yet. The package goes out under the chosen name.
Anatomy
Import the component and assemble its parts:
<NavigationMenu.Root>
<NavigationMenu.List>
<NavigationMenu.Item>
<NavigationMenu.Trigger>
<NavigationMenu.Icon />
</NavigationMenu.Trigger>
<NavigationMenu.Content>
<NavigationMenu.Link />
</NavigationMenu.Content>
</NavigationMenu.Item>
</NavigationMenu.List>
<NavigationMenu.Portal>
<NavigationMenu.Positioner>
<NavigationMenu.Popup>
<NavigationMenu.Arrow />
<NavigationMenu.Viewport />
</NavigationMenu.Popup>
</NavigationMenu.Positioner>
</NavigationMenu.Portal>
</NavigationMenu.Root>
// Not in this example: NavigationMenu.BackdropExamples
Nested
A Root inside a Content part makes a second level that opens to the side.
Nested Inline
A second level that stays in the same panel: List and Viewport with a defaultValue, no Portal.
API reference
28 props across 13 parts, in React syntax. className, style, render are listed once, under Shared props.
ArrowNavigationMenu.Arrow
Displays an element pointing toward the navigation menu's current anchor. Renders a <div>.
| Data attribute | Description |
|---|---|
data-open | Present when the popup is open. |
data-closed | Present when the popup is closed. |
data-side | Indicates which side the popup is positioned relative to the trigger. |
data-align | Indicates how the popup is aligned relative to specified side. |
data-uncentered | Present when the popup arrow is uncentered. |
BackdropNavigationMenu.Backdrop
A backdrop for the navigation menu popup. Renders a <div>.
| Data attribute | Description |
|---|---|
data-open | Present when the popup is open. |
data-closed | Present when the popup is closed. |
data-starting-style | Present when the popup begins animating in. |
data-ending-style | Present when the popup is animating out. |
ContentNavigationMenu.Content
A container for the content of the navigation menu item that is moved into the popup when the item is active. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
keepMountedWhether to keep the content mounted in the DOM while the popup is closed. | boolean | false |
| Data attribute | Description |
|---|---|
data-open | Present when the popup is open. |
data-closed | Present when the popup is closed. |
data-starting-style | Present when the content begins animating in. |
data-ending-style | Present when the content is animating out. |
data-activation-direction | Which direction another trigger was activated from. |
IconNavigationMenu.Icon
An icon that indicates that the trigger button opens a menu.
| Data attribute | Description |
|---|---|
data-popup-open | Present when the navigation menu is open and the item is active. |
ItemNavigationMenu.Item
An individual navigation menu item. Renders a <li>.
| Prop | Type | Default |
|---|---|---|
valueA unique value that identifies this navigation menu item. | any | — |
LinkNavigationMenu.Link
A link in the navigation menu that can be used to navigate to a different page or section. Renders an <a>.
| Prop | Type | Default |
|---|---|---|
closeOnClickWhether to close the navigation menu when the link is clicked. | boolean | false |
activeWhether the link is the currently active page. | boolean | false |
| Data attribute | Description |
|---|---|
data-active | Present when the link is the currently active page. |
ListNavigationMenu.List
Contains a list of navigation menu items. Renders an <ul>.
PopupNavigationMenu.Popup
A container for the navigation menu contents. Renders a <nav>.
| Data attribute | Description |
|---|---|
data-open | Present when the popup is open. |
data-closed | Present when the popup is closed. |
data-starting-style | Present when the popup begins animating in. |
data-ending-style | Present when the popup is animating out. |
data-anchor-hidden | Present when the anchor is hidden. |
data-side | Indicates which side the popup is positioned relative to the trigger. |
data-align | Indicates how the popup is aligned relative to the specified side. |
| CSS variable | Description |
|---|---|
--popup-width | The fixed width of the popup element. |
--popup-height | The fixed height of the popup element. |
PortalNavigationMenu.Portal
A portal element that moves the popup to a different part of the DOM. By default, the portal element is appended to <body>. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
containerA parent element to render the portal element into. | HTMLElement | ShadowRoot | React.RefObject<HTMLElement | ShadowRoot | null> | null | — |
keepMountedWhether to keep the portal mounted in the DOM while the popup is hidden. | boolean | false |
PositionerNavigationMenu.Positioner
Positions the navigation menu against the currently active trigger. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
disableAnchorTrackingWhether to disable the popup from tracking any layout shift of its positioning anchor. | boolean | false |
alignHow to align the popup relative to the specified side. | Align | 'center' |
alignOffsetAdditional offset along the alignment axis in pixels. | number | OffsetFunction | 0 |
sideWhich side of the anchor element to align the popup against. | Side | 'bottom' |
sideOffsetDistance between the anchor and the popup in pixels. | number | OffsetFunction | 0 |
arrowPaddingMinimum distance to maintain between the arrow and the edges of the popup. | number | 5 |
anchorAn element to position the popup against. | Element | VirtualElement | React.RefObject<Element | null> | (() => Element | VirtualElement | null) | null | — |
collisionAvoidanceDetermines how to handle collisions when positioning the popup. | CollisionAvoidance | — |
collisionBoundaryAn element or a rectangle that delimits the area that the popup is confined to. | Boundary | 'clipping-ancestors' |
collisionPaddingAdditional space to maintain from the edge of the collision boundary. | Padding | 5 |
stickyWhether to maintain the popup in the viewport after | boolean | false |
positionMethodDetermines which CSS position property to use. | "absolute" | "fixed" | 'absolute' |
| Data attribute | Description |
|---|---|
data-open | Present when the popup is open. |
data-closed | Present when the popup is closed. |
data-anchor-hidden | Present when the anchor is hidden. |
data-side | Indicates which side the popup is positioned relative to the trigger. |
data-align | Indicates how the popup is aligned relative to the specified side. |
data-instant | Present if animations should be instant. |
| CSS variable | Description |
|---|---|
--available-width | The available width between the trigger and the edge of the viewport. |
--available-height | The available height between the trigger and the edge of the viewport. |
--anchor-width | The anchor's width. |
--anchor-height | The anchor's height. |
--transform-origin | The coordinates that this element is anchored to. Used for animations and transitions. |
--positioner-width | The fixed width of the positioner element. |
--positioner-height | The fixed height of the positioner element. |
RootNavigationMenu.Root
Groups all parts of the navigation menu. at the root, or <div> element when nested. Renders a <nav>.
| Prop | Type | Default |
|---|---|---|
defaultValueThe uncontrolled value of the item that should be initially selected. | TValue | null | null |
valueThe controlled value of the navigation menu item that should be currently open. | TValue | null | null |
onValueChangeCallback fired when the value changes. | ((value: TValue | null, eventDetails: NavigationMenuRootChangeEventDetails) => void) | — |
actionsRefA ref to imperative actions. | React.RefObject<NavigationMenuRootActions | null> | — |
onOpenChangeCompleteEvent handler called after any animations complete when the navigation menu is closed. | ((open: boolean) => void) | — |
delayHow long to wait before opening the navigation popup. | number | 50 |
closeDelayHow long to wait before closing the navigation popup. | number | 50 |
orientationThe orientation of the navigation menu. | "horizontal" | "vertical" | 'horizontal' |
TriggerNavigationMenu.Trigger
Opens the navigation menu popup when hovered or clicked, revealing the associated content. Renders a <button>.
| Prop | Type | Default |
|---|---|---|
nativeButtonWhether the component renders a native <button> element when replacing it | boolean | true |
disabledWhether the component should ignore user interaction. | boolean | false |
| Data attribute | Description |
|---|---|
data-popup-open | Present when the corresponding navigation menu is open. |
data-pressed | Present when the trigger is pressed. |
data-disabled | Present when the trigger is disabled. |
ViewportNavigationMenu.Viewport
The clipping viewport of the navigation menu's current content. Renders a <div>.
Shared props
Every part that renders an element takes these.
| Prop | Type |
|---|---|
classNameCSS class applied to the element, or a function that
returns a class based on the component's state. | string | ((state: State) => string | undefined) |
styleStyle applied to the element, or a function that
returns a style object based on the component's state. | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) |
renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component. | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State> |
Keyboard and accessibility
Keyboard
| Keys | Does | Part |
|---|---|---|
| ArrowDownEnterSpace | Opens the item's content and keeps focus on the trigger | Trigger |
| ArrowLeftArrowRight | Moves between the triggers and links of the list | List |
| ArrowDownArrowUp | Moves between the triggers of a nested menu | List |
| Escape | Closes the content and returns focus to its trigger | Trigger |
Accessibility
| Part | Sets | So that |
|---|---|---|
| Root | renders a <nav> | the menu is a navigation landmark |
| List | renders a <ul>, each Item an <li> | a screen reader counts the entries |
| Trigger | aria-expanded, aria-controls to the popup while its content is open | a screen reader says whether the panel is open and where it is |
| Link | aria-current="page" while active | the link to the current page is announced as such |
| Icon | aria-hidden="true" | the decorative chevron is not read |
| Arrow | aria-hidden="true" | the decorative arrow is not read |
| Backdrop | role="presentation" | the overlay is not read |
Focus order
- Each Trigger and top-level Link is in the tab order; arrow keys also move between them.
- Opening with a key keeps focus on Trigger;
Tabthen moves into the open content. Escapecloses the content and returns focus to its Trigger.