返回项目目录
开发工具精选项目

Radix UI

无样式、可访问且高度可组合的 React UI 原语,为设计系统处理焦点、键盘和复杂交互。

主要语言TypeScript
开源许可MIT
项目类型开发工具
维护状态活跃维护
OVERVIEW

项目概述

Radix Primitives 提供 Dialog、Select、Dropdown Menu、Tabs 等低层 React 组件,不预设视觉样式,却封装了 WAI-ARIA 语义、焦点管理、键盘导航与弹层定位等复杂行为。

Radix UI 的 Primitives 是采用 MIT 许可证的低层 React 组件库,目标是帮助团队构建高质量、可访问的应用和设计系统。它把 Dialog、Popover、Select、Dropdown Menu 等复杂控件拆成可组合的 Parts,处理 WAI-ARIA 语义、键盘导航、焦点管理、Portal 和碰撞检测,同时不提供固定视觉样式。官方推荐安装可 Tree Shaking 的统一 radix-ui 包,也允许按 Primitive 单独安装;团队可以使用普通 CSS、Tailwind CSS、CSS-in-JS 或其他方案完成自己的视觉层。

统一包版本radix-ui 1.6.7
核心定位无样式 React Primitives
可访问性WAI-ARIA 模式
FEATURES

主要特点

Radix UI 专注于把难以正确实现的交互与可访问性行为沉淀为可组合原语。

01

WAI-ARIA 行为基础

在适用场景遵循 WAI-ARIA Authoring Practices,处理角色、属性、键盘交互与辅助技术预期。

02

焦点管理

Dialog、Alert Dialog、Popover 等组件提供焦点进入、循环、关闭恢复和外部交互等复杂基础行为。

03

完全无样式

组件不携带品牌视觉,可通过 className 配合 CSS、Tailwind、CSS Modules 或 CSS-in-JS 自由设计。

04

可组合 Parts

Root、Trigger、Portal、Overlay、Content、Title 等部件允许团队按实际结构组装并封装自己的组件 API。

05

受控与非受控模式

多数有状态 Primitive 默认支持 defaultValue 或 defaultOpen,也可以通过 value、open 和回调接入应用状态。

06

asChild 组合

asChild 可把 Radix 行为和属性合并到自定义元素或路由链接,避免无意义包装并保留语义化 DOM。

07

状态与布局数据属性

data-state、data-side、data-align 等属性把运行状态暴露给样式层,可用于状态样式和进入、退出动画。

08

弹层与碰撞处理

Popover、Tooltip、Menu 等 Primitive 支持 Portal、边界碰撞、对齐、偏移和可用空间变量。

09

一致的 TypeScript API

组件采用相似的 Parts、受控属性和事件命名,并提供完整类型,便于设计系统包装和编辑器提示。

10

渐进式安装

可安装 Tree Shaking 的统一 radix-ui 包,也可只安装 @radix-ui/react-dialog 等独立包。

11

SSR 与现代 React

Primitives 支持服务端渲染,可用于 Next.js、Remix 等 React 框架,并兼容现代 React 版本。

USE CASES

适用场景

团队已有视觉规范,但不希望重复实现弹层、焦点和键盘交互时,Radix Primitives 很有价值。

企业设计系统

设计系统团队可以包装稳定交互原语,统一视觉、令牌、API、文档与应用级可访问性规范。

高度品牌化的 SaaS

无需接受现成组件库的视觉语言,也不必从头实现 Select、Dialog、Menu 和 Tooltip 等复杂行为。

复杂表单和设置界面

Checkbox、Radio Group、Select、Slider、Switch、Tabs 和 Label 能组成键盘友好的输入流程。

导航与操作菜单

Dropdown Menu、Context Menu、Menubar 和 Navigation Menu 覆盖方向键、Typeahead、子菜单和焦点切换。

弹层密集的 Web 应用

Dialog、Alert Dialog、Popover、Hover Card 和 Tooltip 可统一 Portal、关闭行为与层级交互。

渐进改造现有 React 项目

可以只替换最难维护的一个控件,并沿用原有样式体系,不要求一次引入完整设计语言。

EVALUATION

优点与注意事项

技术选型不仅要看能力,也要理解它带来的团队成本。

主要优点

Radix UI 擅长的地方

  • 封装键盘导航、焦点管理和 WAI-ARIA 语义等高风险交互细节
  • 完全无样式,可适配任何品牌视觉和主流 React 样式方案
  • Parts 架构粒度细,便于包装成团队自己的设计系统组件
  • 受控与非受控模式兼顾快速使用和复杂状态管理
  • data-state 等属性让状态样式与动画不必复制组件逻辑
  • 统一包可 Tree Shaking,也保留单独安装 Primitive 的灵活性
  • TypeScript API、文档和组件间约定一致,学习可迁移

需要注意

采用前应考虑的问题

无样式也包括功能性样式

Dialog Overlay 默认不会自动铺满视口。定位、尺寸、滚动、层级和动画等功能性 CSS 也需要团队实现。

可访问原语不等于最终页面可访问

开发者仍需提供标签、标题、说明、错误信息和合理内容顺序,并测试组合后的完整任务流程。

仅面向 React

Radix Primitives 不是跨框架 Web Components。Vue、Svelte 或纯 HTML 项目需要选择对应生态方案。

Parts 组合会增加模板长度

一个完整 Dialog 通常包含多个显式部件。产品团队应在设计系统层包装常用结构,而不是让每个页面重复组装。

asChild 有严格组合要求

作为 Child 的自定义组件必须透传 Radix 注入的 Props,并在需要时正确转发 Ref,否则事件、ARIA 或焦点行为会失效。

独立包版本需要一起管理

分别安装多个 @radix-ui 包时应同步更新,避免共享依赖重复和版本组合问题;一般优先使用统一 radix-ui 包。

Portal 与层级需要统一治理

弹层进入 body 后会涉及 z-index、滚动锁定、嵌套弹层、主题作用域和测试环境,应建立应用级 Overlay 规范。

覆盖默认行为要谨慎

onPointerDownOutside、onOpenAutoFocus 等事件允许深度控制,但取消默认行为可能破坏键盘和辅助技术预期。

它不提供完整视觉设计系统

颜色、排版、间距、图标、响应式规范和组件视觉状态都由团队负责;需要开箱即用外观时应评估 Radix Themes 或上层组件库。

QUICK START

快速开始

下面使用统一 radix-ui 包创建一个带完整焦点管理、标题和说明的 Dialog,并用 CSS 定义视觉与动画。

1安装统一 Radix UI 包
bash
npm install radix-ui
2创建可访问的 Dialog
tsx
import { Dialog } from "radix-ui";
import "./dialog.css";

export function ProfileDialog() {
  return (
    <Dialog.Root>
      <Dialog.Trigger className="button">编辑资料</Dialog.Trigger>

      <Dialog.Portal>
        <Dialog.Overlay className="dialog-overlay" />
        <Dialog.Content className="dialog-content">
          <Dialog.Title className="dialog-title">
            编辑资料
          </Dialog.Title>
          <Dialog.Description className="dialog-description">
            修改姓名并保存。完成后焦点会回到打开按钮。
          </Dialog.Description>

          <label className="field">
            <span>姓名</span>
            <input name="name" autoComplete="name" />
          </label>

          <div className="actions">
            <Dialog.Close className="button secondary">
              取消
            </Dialog.Close>
            <button className="button" type="submit">
              保存
            </button>
          </div>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}
3添加布局与状态样式
css
.dialog-overlay {
  position: fixed;
  inset: 0;
  background: rgb(0 0 0 / 0.5);
  animation: fade-in 160ms ease-out;
}

.dialog-content {
  position: fixed;
  top: 50%;
  left: 50%;
  width: min(28rem, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow: auto;
  transform: translate(-50%, -50%);
  border-radius: 1rem;
  background: white;
  padding: 1.5rem;
  box-shadow: 0 24px 80px rgb(0 0 0 / 0.25);
}

.dialog-content[data-state="closed"] {
  animation: fade-out 120ms ease-in;
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fade-out {
  from { opacity: 1; }
  to { opacity: 0; }
}
4使用受控状态处理异步提交
tsx
import { useState } from "react";
import { Dialog } from "radix-ui";

export function ControlledDialog() {
  const [open, setOpen] = useState(false);

  async function handleSubmit(event: React.FormEvent) {
    event.preventDefault();
    await saveProfile();
    setOpen(false);
  }

  return (
    <Dialog.Root open={open} onOpenChange={setOpen}>
      <Dialog.Trigger>编辑</Dialog.Trigger>
      <Dialog.Portal>
        <Dialog.Overlay />
        <Dialog.Content>
          <Dialog.Title>编辑资料</Dialog.Title>
          <form onSubmit={handleSubmit}>
            <button type="submit">保存</button>
          </form>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}
5通过 asChild 复用自定义按钮
tsx
import { forwardRef } from "react";
import { Dialog } from "radix-ui";

const PrimaryButton = forwardRef<
  HTMLButtonElement,
  React.ComponentPropsWithoutRef<"button">
>((props, ref) => (
  <button {...props} ref={ref} className="primary-button" />
));

PrimaryButton.displayName = "PrimaryButton";

export function Trigger() {
  return (
    <Dialog.Trigger asChild>
      <PrimaryButton>打开设置</PrimaryButton>
    </Dialog.Trigger>
  );
}
6按 Primitive 子路径导入
tsx
import { Dialog } from "radix-ui/dialog";
import { Tooltip } from "radix-ui/tooltip";

// 统一包支持子路径导入,便于明确模块边界。
export { Dialog, Tooltip };
7运行应用并执行质量检查
bash
npm run dev

# 发布前运行项目自己的类型、测试和构建脚本
npm run typecheck
npm test
npm run build

下一步:Radix 提供的是可访问性基础而不是最终保证。必须为控件提供可理解的 Label、Title 和 Description,并在真实页面中测试键盘、屏幕阅读器、触摸、缩放和高对比度模式。

ALTERNATIVES

类似项目

React 是 Radix 的运行基础,shadcn/ui 则是本站中最常见的 Radix 上层源码组件方案;其他无样式原语列为外部参考。

COMPARISON

Radix UI vs shadcn/ui

Radix Primitives 与 shadcn/ui 经常组合使用,但两者不在同一抽象层:Radix 提供无样式行为原语,shadcn/ui 则分发带 Tailwind 视觉和应用源码所有权的完整组件。

比较维度Radix UIshadcn/ui
核心定位无样式、可访问的 React 行为原语开放源码组件与 Registry 分发平台
安装结果组件实现保留在版本化依赖包中组件源码被复制到应用目录
视觉样式不提供,需要团队从零设计提供 Tailwind CSS 和主题变量的优质默认值
底层基础Radix 自己实现 Primitive 行为可选择 Base UI、Radix 或 React Aria
定制方式组合 Parts、Props、事件与任意样式方案直接修改应用中的组件结构、行为和 Tailwind 类
升级方式更新 npm 依赖并处理 API 变化审阅差异后手动合并或覆盖组件源码
维护责任原语内部修复由 Radix 包更新提供复制后的组件由应用团队直接维护
更适合从零建立独特设计系统和低层组件 API快速获得完整组件并继续深度品牌化
如何选择

如果团队正在构建设计系统基础层,需要完全控制视觉和上层组件 API,Radix Primitives 更适合作为行为底座;如果希望快速得到可直接用于产品的组件,并愿意维护复制后的源码,shadcn/ui 更高效。选择 shadcn/ui 时仍可以把 Radix 作为底层 Base,两者并非必须二选一。

VERIFICATION

资料核验

版本、维护信息与本页采用的官方资料来源。

最后核验2026 年 7 月 29 日
核验版本radix-ui 1.6.7
内容维护Docs100 编辑整理
项目维护状态活跃维护

本页依据 Radix Primitives 官方介绍、可访问性、样式、组合、SSR 与 Dialog 文档,以及 npm Registry 和官方源码仓库整理。统一包与各 Primitive 独立包的版本号不同,页面中的版本指 radix-ui 聚合包。

维护状态核验2026 年 7 月 26 日 · 最近可见代码活动:2026 年 7 月 28 日

官方仓库未归档,核验时最近可见的代码活动日期为 2026 年 7 月 28 日。该状态表示项目近期仍有公开维护活动,不代表固定发布频率或长期支持承诺。

查看官方仓库