A collection of React components for building accessible, customizable navigation menus with keyboard support and flexible layout options
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Trigger and link components that handle user interactions with keyboard and pointer support.
Interactive button element that triggers the display of associated navigation content, with built-in keyboard and pointer event handling.
/**
* Interactive trigger button for menu items with accessibility support
* Handles click, hover, and keyboard interactions to open/close menu content
* Automatically manages ARIA attributes and focus states
*/
const NavigationMenuTrigger: React.ForwardRefExoticComponent<
NavigationMenuTriggerProps & React.RefAttributes<HTMLButtonElement>
>;
interface NavigationMenuTriggerProps
extends React.ComponentPropsWithoutRef<"button"> {}Key Features:
aria-expanded, aria-controls)Usage Examples:
import {
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuTrigger,
NavigationMenuContent
} from "@radix-ui/react-navigation-menu";
function TriggerExample() {
return (
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger className="nav-trigger">
Products
</NavigationMenuTrigger>
<NavigationMenuContent>
Product information here
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuTrigger
onPointerEnter={() => console.log("Hover started")}
onPointerLeave={() => console.log("Hover ended")}
onClick={() => console.log("Clicked")}
>
Services
</NavigationMenuTrigger>
<NavigationMenuContent>
Service information here
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
);
}
// Custom trigger with disabled state
function DisabledTriggerExample() {
return (
<NavigationMenuItem>
<NavigationMenuTrigger disabled>
Coming Soon
</NavigationMenuTrigger>
</NavigationMenuItem>
);
}Navigation link component with active state support and custom selection event handling.
/**
* Navigation link component with active state and selection events
* @param active - Whether this link represents the current page/section
* @param onSelect - Custom selection event handler (called before navigation)
*/
const NavigationMenuLink: React.ForwardRefExoticComponent<
NavigationMenuLinkProps & React.RefAttributes<HTMLAnchorElement>
>;
interface NavigationMenuLinkProps
extends Omit<React.ComponentPropsWithoutRef<"a">, "onSelect"> {
active?: boolean;
onSelect?: (event: Event) => void;
}Key Features:
aria-current="page" when activeUsage Examples:
import {
NavigationMenu,
NavigationMenuList,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuTrigger,
NavigationMenuContent
} from "@radix-ui/react-navigation-menu";
function LinkExample() {
const [currentPage, setCurrentPage] = React.useState("/home");
return (
<NavigationMenu>
<NavigationMenuList>
{/* Direct navigation link */}
<NavigationMenuItem>
<NavigationMenuLink
href="/home"
active={currentPage === "/home"}
onSelect={(event) => {
console.log("Navigating to home");
setCurrentPage("/home");
}}
>
Home
</NavigationMenuLink>
</NavigationMenuItem>
{/* Links within content */}
<NavigationMenuItem>
<NavigationMenuTrigger>Products</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuLink
href="/products/web"
active={currentPage === "/products/web"}
>
Web Development
</NavigationMenuLink>
<NavigationMenuLink
href="/products/mobile"
active={currentPage === "/products/mobile"}
>
Mobile Apps
</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
{/* External link */}
<NavigationMenuItem>
<NavigationMenuLink
href="https://example.com"
target="_blank"
rel="noopener noreferrer"
onSelect={(event) => {
console.log("Opening external link");
}}
>
External Resource
</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
);
}
// Link with custom selection handling
function CustomLinkExample() {
return (
<NavigationMenuItem>
<NavigationMenuLink
href="/custom"
onSelect={(event) => {
// Prevent default navigation
event.preventDefault();
// Custom handling (e.g., modal, confirmation)
if (confirm("Are you sure you want to navigate?")) {
window.location.href = "/custom";
}
}}
>
Custom Link
</NavigationMenuLink>
</NavigationMenuItem>
);
}Both trigger and link components support comprehensive event handling:
// Pointer events
onPointerEnter?: (event: React.PointerEvent) => void;
onPointerMove?: (event: React.PointerEvent) => void;
onPointerLeave?: (event: React.PointerEvent) => void;
// Click and keyboard events
onClick?: (event: React.MouseEvent) => void;
onKeyDown?: (event: React.KeyboardEvent) => void;
// Focus events
onFocus?: (event: React.FocusEvent) => void;
onBlur?: (event: React.FocusEvent) => void;// Custom selection event
onSelect?: (event: Event) => void;
// Standard anchor events
onClick?: (event: React.MouseEvent) => void;
onKeyDown?: (event: React.KeyboardEvent) => void;
onFocus?: (event: React.FocusEvent) => void;Interactive elements expose data attributes for styling:
[data-state="open"] { /* Trigger is active (content is open) */ }
[data-state="closed"] { /* Trigger is inactive */ }
[data-disabled] { /* Trigger is disabled */ }Usage Example:
.nav-trigger[data-state="open"] {
background-color: var(--accent-color);
color: white;
}
.nav-trigger[data-disabled] {
opacity: 0.5;
cursor: not-allowed;
}[data-active] { /* Link represents the current page */ }Usage Example:
.nav-link[data-active] {
font-weight: bold;
color: var(--primary-color);
}
.nav-link[data-active]::after {
content: "";
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
background: var(--primary-color);
}Install with Tessl CLI
npx tessl i tessl/npm-radix-ui--react-navigation-menu