Components

导航菜单

¥Navigation Menu

用于网站导航的链接集合。

import * as React from "react";
import { NavigationMenu } from "radix-ui";
import classNames from "classnames";
import { CaretDownIcon } from "@radix-ui/react-icons";
import "./styles.css";
const NavigationMenuDemo = () => {
return (
<NavigationMenu.Root className="NavigationMenuRoot">
<NavigationMenu.List className="NavigationMenuList">
<NavigationMenu.Item>
<NavigationMenu.Trigger className="NavigationMenuTrigger">
Learn <CaretDownIcon className="CaretDown" aria-hidden />
</NavigationMenu.Trigger>
<NavigationMenu.Content className="NavigationMenuContent">
<ul className="List one">
<li style={{ gridRow: "span 3" }}>
<NavigationMenu.Link asChild>
<a className="Callout" href="/">
<svg aria-hidden width="38" height="38" viewBox="0 0 25 25" fill="white" >
<path d="M12 25C7.58173 25 4 21.4183 4 17C4 12.5817 7.58173 9 12 9V25Z"></path>
<path d="M12 0H4V8H12V0Z"></path>
<path d="M17 8C19.2091 8 21 6.20914 21 4C21 1.79086 19.2091 0 17 0C14.7909 0 13 1.79086 13 4C13 6.20914 14.7909 8 17 8Z"></path>
</svg>
<div className="CalloutHeading">Radix Primitives</div>
<p className="CalloutText">
Unstyled, accessible components for React.
</p>
</a>
</NavigationMenu.Link>
</li>
<ListItem href="https://stitches.dev/" title="Stitches">
CSS-in-JS with best-in-class developer experience.
</ListItem>
<ListItem href="/colors" title="Colors">
Beautiful, thought-out palettes with auto dark mode.
</ListItem>
<ListItem href="https://icons.radix-ui.com/" title="Icons">
A crisp set of 15x15 icons, balanced and consistent.
</ListItem>
</ul>
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Trigger className="NavigationMenuTrigger">
Overview <CaretDownIcon className="CaretDown" aria-hidden />
</NavigationMenu.Trigger>
<NavigationMenu.Content className="NavigationMenuContent">
<ul className="List two">
<ListItem title="Introduction" href="/primitives/docs/overview/introduction" >
Build high-quality, accessible design systems and web apps.
</ListItem>
<ListItem title="Getting started" href="/primitives/docs/overview/getting-started" >
A quick tutorial to get you up and running with Radix
Primitives.
</ListItem>
<ListItem title="Styling" href="/primitives/docs/guides/styling">
Unstyled and compatible with any styling solution.
</ListItem>
<ListItem title="Animation" href="/primitives/docs/guides/animation" >
Use CSS keyframes or any animation library of your choice.
</ListItem>
<ListItem title="Accessibility" href="/primitives/docs/overview/accessibility" >
Tested in a range of browsers and assistive technologies.
</ListItem>
<ListItem title="Releases" href="/primitives/docs/overview/releases" >
Radix Primitives releases and their changelogs.
</ListItem>
</ul>
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Link className="NavigationMenuLink" href="https://github.com/radix-ui" >
Github
</NavigationMenu.Link>
</NavigationMenu.Item>
<NavigationMenu.Indicator className="NavigationMenuIndicator">
<div className="Arrow" />
</NavigationMenu.Indicator>
</NavigationMenu.List>
<div className="ViewportPosition">
<NavigationMenu.Viewport className="NavigationMenuViewport" />
</div>
</NavigationMenu.Root>
);
};
const ListItem = React.forwardRef(
({ className, children, title, ...props }, forwardedRef) => (
<li>
<NavigationMenu.Link asChild>
<a className={classNames("ListItemLink", className)} {...props} ref={forwardedRef} >
<div className="ListItemHeading">{title}</div>
<p className="ListItemText">{children}</p>
</a>
</NavigationMenu.Link>
</li>
),
);
export default NavigationMenuDemo;

Features

    Can be controlled or uncontrolled.

    Flexible layout structure with managed tab focus.

    Supports submenus.

    Optional active item indicator.

    Full keyboard navigation.

    Exposes CSS variables for advanced animation.

    Supports custom timings.

安装

¥Installation

从命令行安装组件。

¥Install the component from your command line.

npm install @radix-ui/react-navigation-menu

结构

¥Anatomy

导入所有部分并将它们组合在一起。

¥Import all parts and piece them together.

import { NavigationMenu } from "radix-ui";
export default () => (
<NavigationMenu.Root>
<NavigationMenu.List>
<NavigationMenu.Item>
<NavigationMenu.Trigger />
<NavigationMenu.Content>
<NavigationMenu.Link />
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Link />
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Trigger />
<NavigationMenu.Content>
<NavigationMenu.Sub>
<NavigationMenu.List />
<NavigationMenu.Viewport />
</NavigationMenu.Sub>
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Indicator />
</NavigationMenu.List>
<NavigationMenu.Viewport />
</NavigationMenu.Root>
);

API 参考

¥API Reference

¥Root

包含导航菜单的所有部分。

¥Contains all the parts of a navigation menu.

PropTypeDefault
defaultValue
string
No default value
value
string
No default value
onValueChange
function
No default value
delayDuration
number
200
skipDelayDuration
number
300
dir
enum
No default value
orientation
enum
"horizontal"
Data attributeValues
[data-orientation]"vertical" | "horizontal"

Sub

表示子菜单。嵌套时使用它来代替根部件创建子菜单。

¥Signifies a submenu. Use it in place of the root part when nested to create a submenu.

PropTypeDefault
defaultValue
string
No default value
value
string
No default value
onValueChange
function
No default value
orientation
enum
"horizontal"
Data attributeValues
[data-orientation]"vertical" | "horizontal"

列表

¥List

包含顶层菜单项。

¥Contains the top level menu items.

PropTypeDefault
asChild
boolean
false
Data attributeValues
[data-orientation]"vertical" | "horizontal"

项目

¥Item

顶层菜单项,包含链接或触发器及其内容组合。

¥A top level menu item, contains a link or trigger with content combination.

PropTypeDefault
asChild
boolean
false
value
string
No default value

触发器

¥Trigger

切换内容的按钮。

¥The button that toggles the content.

PropTypeDefault
asChild
boolean
false
Data attributeValues
[data-state]"open" | "closed"
[data-disabled]

Present when disabled

内容

¥Content

包含与每个触发器关联的内容。

¥Contains the content associated with each trigger.

PropTypeDefault
asChild
boolean
false
onEscapeKeyDown
function
No default value
onPointerDownOutside
function
No default value
onFocusOutside
function
No default value
onInteractOutside
function
No default value
forceMount
boolean
No default value
Data attributeValues
[data-state]"open" | "closed"
[data-motion]"to-start" | "to-end" | "from-start" | "from-end"
[data-orientation]"vertical" | "horizontal"

链接

¥Link

一个导航链接。

¥A navigational link.

PropTypeDefault
asChild
boolean
false
active
boolean
false
onSelect
function
No default value
Data attributeValues
[data-active]

Present when active

指示符

¥Indicator

用于在列表下方渲染的可选指示元素,用于高亮当前活动的触发器。

¥An optional indicator element that renders below the list, is used to highlight the currently active trigger.

PropTypeDefault
asChild
boolean
false
forceMount
boolean
No default value
Data attributeValues
[data-state]"visible" | "hidden"
[data-orientation]"vertical" | "horizontal"

视口

¥Viewport

用于在列表外部渲染活动内容的可选视口元素。

¥An optional viewport element that is used to render active content outside of the list.

PropTypeDefault
asChild
boolean
false
forceMount
boolean
No default value
Data attributeValues
[data-state]"open" | "closed"
[data-orientation]"vertical" | "horizontal"
CSS VariableDescription
--radix-navigation-menu-viewport-widthThe width of the viewport when visible/hidden, computed from the active content
--radix-navigation-menu-viewport-heightThe height of the viewport when visible/hidden, computed from the active content

示例

¥Examples

垂直

¥Vertical

你可以使用 orientation 属性创建垂直菜单。

¥You can create a vertical menu by using the orientation prop.

<NavigationMenu.Root orientation="vertical">
<NavigationMenu.List>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Item one</NavigationMenu.Trigger>
<NavigationMenu.Content>Item one content</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Item two</NavigationMenu.Trigger>
<NavigationMenu.Content>Item Two content</NavigationMenu.Content>
</NavigationMenu.Item>
</NavigationMenu.List>
</NavigationMenu.Root>

灵活布局

¥Flexible layouts

当你需要额外控制 Content 的渲染位置时,请使用 Viewport 组件。当你的设计需要调整 DOM 结构,或者你需要灵活性来实现 高级动画 时,这会很有帮助。标签焦点将自动保持。

¥Use the Viewport part when you need extra control over where Content is rendered. This can be helpful when your design requires an adjusted DOM structure or if you need flexibility to achieve advanced animation. Tab focus will be maintained automatically.

<NavigationMenu.Root>
<NavigationMenu.List>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Item one</NavigationMenu.Trigger>
<NavigationMenu.Content>Item one content</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Item two</NavigationMenu.Trigger>
<NavigationMenu.Content>Item two content</NavigationMenu.Content>
</NavigationMenu.Item>
</NavigationMenu.List>
{/* NavigationMenu.Content will be rendered here when active */}
<NavigationMenu.Viewport />
</NavigationMenu.Root>

使用指示器

¥With indicator

你可以使用可选的 Indicator 部分来高亮当前活动的 Trigger,这在你想要提供动画视觉提示(例如箭头或高亮)来配合 Viewport 时非常有用。

¥You can use the optional Indicator part to highlight the currently active Trigger, this is useful when you want to provide an animated visual cue such as an arrow or highlight to accompany the Viewport.

// index.jsx
import { NavigationMenu } from "radix-ui";
import "./styles.css";
export default () => (
<NavigationMenu.Root>
<NavigationMenu.List>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Item one</NavigationMenu.Trigger>
<NavigationMenu.Content>Item one content</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Item two</NavigationMenu.Trigger>
<NavigationMenu.Content>Item two content</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Indicator className="NavigationMenuIndicator" />
</NavigationMenu.List>
<NavigationMenu.Viewport />
</NavigationMenu.Root>
);
/* styles.css */
.NavigationMenuIndicator {
background-color: grey;
}
.NavigationMenuIndicator[data-orientation="horizontal"] {
height: 3px;
transition:
width,
transform,
250ms ease;
}

与子菜单一起使用

¥With submenus

通过嵌套 NavigationMenu 并使用 Sub 部分代替其 Root 来创建子菜单。子菜单的工作方式与 Root 导航菜单不同,与 Tabs 类似,因为其中一个项目应始终处于活动状态,因此请务必分配并设置 defaultValue

¥Create a submenu by nesting your NavigationMenu and using the Sub part in place of its Root. Submenus work differently to Root navigation menus and are similar to Tabs in that one item should always be active, so be sure to assign and set a defaultValue.

<NavigationMenu.Root>
<NavigationMenu.List>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Item one</NavigationMenu.Trigger>
<NavigationMenu.Content>Item one content</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Item two</NavigationMenu.Trigger>
<NavigationMenu.Content>
<NavigationMenu.Sub defaultValue="sub1">
<NavigationMenu.List>
<NavigationMenu.Item value="sub1">
<NavigationMenu.Trigger>Sub item one</NavigationMenu.Trigger>
<NavigationMenu.Content>
Sub item one content
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item value="sub2">
<NavigationMenu.Trigger>Sub item two</NavigationMenu.Trigger>
<NavigationMenu.Content>
Sub item two content
</NavigationMenu.Content>
</NavigationMenu.Item>
</NavigationMenu.List>
</NavigationMenu.Sub>
</NavigationMenu.Content>
</NavigationMenu.Item>
</NavigationMenu.List>
</NavigationMenu.Root>

使用客户端路由

¥With client side routing

如果你需要使用路由包提供的 Link 组件,我们建议你通过自定义组件与 NavigationMenu.Link 进行组合。这将确保可访问性和一致的键盘控制。以下是使用 Next.js 的示例:

¥If you need to use the Link component provided by your routing package then we recommend composing with NavigationMenu.Link via a custom component. This will ensure accessibility and consistent keyboard control is maintained. Here's an example using Next.js:

// index.jsx
import { usePathname } from "next/navigation";
import NextLink from "next/link";
import { NavigationMenu } from "radix-ui";
import "./styles.css";
const Link = ({ href, ...props }) => {
const pathname = usePathname();
const isActive = href === pathname;
return (
<NavigationMenu.Link asChild active={isActive}>
<NextLink href={href} className="NavigationMenuLink" {...props} />
</NavigationMenu.Link>
);
};
export default () => (
<NavigationMenu.Root>
<NavigationMenu.List>
<NavigationMenu.Item>
<Link href="/">Home</Link>
</NavigationMenu.Item>
<NavigationMenu.Item>
<Link href="/about">About</Link>
</NavigationMenu.Item>
</NavigationMenu.List>
</NavigationMenu.Root>
);
/* styles.css */
.NavigationMenuLink {
text-decoration: none;
}
.NavigationMenuLink[data-active] {
text-decoration: "underline";
}

高级动画

¥Advanced animation

我们公开了 --radix-navigation-menu-viewport-[width|height]data-motion['from-start'|'to-start'|'from-end'|'to-end'] 属性,以便你根据进入/退出方向为 Viewport 的大小和 Content 的位置设置动画。

¥We expose --radix-navigation-menu-viewport-[width|height] and data-motion['from-start'|'to-start'|'from-end'|'to-end'] attributes to allow you to animate Viewport size and Content position based on the enter/exit direction.

结合 position: absolute;,你可以在项目之间移动时创建流畅的重叠动画效果。

¥Combining these with position: absolute; allows you to create smooth overlapping animation effects when moving between items.

// index.jsx
import { NavigationMenu } from "radix-ui";
import "./styles.css";
export default () => (
<NavigationMenu.Root>
<NavigationMenu.List>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Item one</NavigationMenu.Trigger>
<NavigationMenu.Content className="NavigationMenuContent">
Item one content
</NavigationMenu.Content>
</NavigationMenu.Item>
<NavigationMenu.Item>
<NavigationMenu.Trigger>Item two</NavigationMenu.Trigger>
<NavigationMenu.Content className="NavigationMenuContent">
Item two content
</NavigationMenu.Content>
</NavigationMenu.Item>
</NavigationMenu.List>
<NavigationMenu.Viewport className="NavigationMenuViewport" />
</NavigationMenu.Root>
);
/* styles.css */
.NavigationMenuContent {
position: absolute;
top: 0;
left: 0;
animation-duration: 250ms;
animation-timing-function: ease;
}
.NavigationMenuContent[data-motion="from-start"] {
animation-name: enterFromLeft;
}
.NavigationMenuContent[data-motion="from-end"] {
animation-name: enterFromRight;
}
.NavigationMenuContent[data-motion="to-start"] {
animation-name: exitToLeft;
}
.NavigationMenuContent[data-motion="to-end"] {
animation-name: exitToRight;
}
.NavigationMenuViewport {
position: relative;
width: var(--radix-navigation-menu-viewport-width);
height: var(--radix-navigation-menu-viewport-height);
transition:
width,
height,
250ms ease;
}
@keyframes enterFromRight {
from {
opacity: 0;
transform: translateX(200px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes enterFromLeft {
from {
opacity: 0;
transform: translateX(-200px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes exitToRight {
from {
opacity: 1;
transform: translateX(0);
}
to {
opacity: 0;
transform: translateX(200px);
}
}
@keyframes exitToLeft {
from {
opacity: 1;
transform: translateX(0);
}
to {
opacity: 0;
transform: translateX(-200px);
}
}

可访问性

¥Accessibility

遵循 navigation 角色要求

¥Adheres to the navigation role requirements.

与菜单栏的区别

¥Differences to menubar

NavigationMenu 不应与 menubar 混淆,尽管这个基础组件在通俗意义上与 menu 共享名称,指的是一组导航链接,但它不使用 WAI-ARIA menu 角色。这是因为 menumenubars 的行为类似于桌面应用窗口中最常见的原生操作系统菜单,因此它们具有复杂的功能,例如复合焦点管理和首字符导航。

¥NavigationMenu should not be confused with menubar, although this primitive shares the name menu in the colloquial sense to refer to a set of navigation links, it does not use the WAI-ARIA menu role. This is because menu and menubars behave like native operating system menus most commonly found in desktop application windows, as such they feature complex functionality like composite focus management and first-character navigation.

这些功能通常被认为是 网站导航不需要 的,在最坏的情况下,可能会让熟悉现有网站模式的用户感到困惑。

¥These features are often considered unnecessary for website navigation and at worst can confuse users who are familiar with established website patterns.

有关更多信息,请参阅 W3C 公开导航菜单 示例。

¥See the W3C Disclosure Navigation Menu example for more information.

链接使用和 aria-current

¥Link usage and aria-current

菜单中的所有导航链接务必使用 NavigationMenu.Link,这不仅适用于主列表,也适用于通过 NavigationMenu.Content 渲染的任何内容。这将确保一致的键盘交互和可访问性,同时允许访问 active 属性以设置 aria-current 和活动样式。有关与第三方路由组件配合使用的更多信息,请参阅 本例

¥It's important to use NavigationMenu.Link for all navigational links within a menu, this not only applies to the main list but also within any content rendered via NavigationMenu.Content. This will ensure consistent keyboard interactions and accessibility while also giving access to the active prop for setting aria-current and the active styles. See this example for more information on usage with third party routing components.

键盘交互

¥Keyboard Interactions

KeyDescription
SpaceEnter
When focus is on NavigationMenu.Trigger, opens the content.
Tab
Moves focus to the next focusable element.
ArrowDown
When horizontal and focus is on an open NavigationMenu.Trigger, moves focus into NavigationMenu.Content.
Moves focus to the next NavigationMenu.Trigger or NavigationMenu.Link.
ArrowUp
Moves focus to the previous NavigationMenu.Trigger or NavigationMenu.Link.
ArrowRightArrowLeft
When vertical and focus is on an open NavigationMenu.Trigger, moves focus into its NavigationMenu.Content.
Moves focus to the next / previous NavigationMenu.Trigger or NavigationMenu.Link.
HomeEnd
Moves focus to the first/last NavigationMenu.Trigger or NavigationMenu.Link.
Esc
Closes open NavigationMenu.Content and moves focus to its NavigationMenu.Trigger.