初探 Astryx:Meta 的设计系统
Meta 的开源设计系统 Astryx 汇集 150 多个 React 组件、主题、CLI 设置、自定义层级,以及与 shadcn/ui 和 Base UI 的比较。
Astryx 是 Meta 对其内部孕育多年的设计系统进行开源重构的成果,于 2026 年 6 月 18 日在 Astryx 博客上发布,以 MIT 许可证形式作为公测版(public beta)推出。它提供了超过 150 个符合无障碍标准的 React 组件、七套开箱即用的主题、模板以及一个 CLI,基于 React 19 及以上版本和 StyleX 构建。
如果你曾用 MUI 交付过项目,你大概熟悉这种取舍:组件本身是好用的,但你得花上一个迭代周期去跟 theme 对象搏斗,只为让一个按钮别看着像是别人家的按钮。如果你用的是 shadcn/ui 那套自持源码的方式,你熟悉的是另一种取舍:仓库里躺着四十个组件文件,完全归你所有——但也没有上游可供你拉取某个焦点管理的修复补丁。
Meta 的主张是,Astryx 居于两者之间。功能清单很容易找到;真正决定采用成本的,是那条五级定制阶梯,以及你的团队最终会落在哪一级上。本文将介绍 Astryx 是什么、如何安装与使用、主题机制如何运作、阶梯的每一级各自要付出什么代价,以及它与 shadcn/ui 和 Base UI 相比处于什么位置。
关键要点
- Astryx 需要 React 19 或更高版本,
@astryxdesign/core将react、react-dom和@stylexjs/stylex列为 peer dependencies。 - Astryx 提供两条分发路径:直接引入预编译样式表,或从 TypeScript 与 StyleX 源码构建,使打包器只为你实际引入的组件输出 CSS。
- 定制能力沿五个层级逐步升级,只有最后一级——把组件源码 swizzle 进你自己的仓库——会让你脱离共享的升级路径。
- 组件同时接受带类型的
xstyleprop 和普通的className,而预编译路径不会给你的构建流程增加任何负担:无需打包器插件、无需 PostCSS、无需 Babel 配置。 - Astryx 目前仍是 0.x 版本的公测阶段,尚无稳定版本线,因此 API 变动是一项实实在在的成本。
Astryx 是什么?
Astryx 是一个组件库,但外面还包裹着一整套体系:带类型的 React 组件与预编译 CSS 一同发布,再加上品牌层级的主题化、深色模式、页面模板和一个 CLI,全部作为一组统一的包分发。Meta 的技术说明文章将其定位为一套系统的开源重构版本——该系统在公司内部成长了八年,覆盖 13,000 多个产品,其中约有一半的更新来自内部构建者社区的贡献。样式使用 StyleX 编写,这是 Meta 的编译器,能在构建时将样式对象转换为原子化、无冲突的 CSS。如果你对 CSS-in-JS 的反对意见在于运行时开销,那这一点很关键:浏览器中没有任何样式引擎在运行。
CLI 是与该项目打交道的主要入口,无论使用者是人还是机器。组件文档、设计 token、页面模板、主题工具和升级 codemod 都从它这里出来——你可以从终端调用它、读取它输出的带类型 JSON,或直接 import 它的函数,而 agent 和构建工具走的是同一套 API。项目自称的 “AI-fluent”(AI 友好)和面向 agent 就绪,属于定位表述而非可量化的结果;Meta 描述的评测框架在两篇发布文章中都没有公开任何结果。
实际如何使用 Astryx?
React 19 是底线:@astryxdesign/core 将 react 和 react-dom 的 19.0.0 及以上版本列为 peer dependencies。这是第一道门槛。第二道门槛是成熟度:@astryxdesign/core 在 npm 上发布于 0.x 版本线,而 @astryxdesign/vega 和 @astryxdesign/charts 只在 @canary dist-tag 下提供真正的构建产物,它们的 latest tag 仍然指向一个占位发布。
安装 core 包、一个主题包和 StyleX peer 依赖,并把 CLI 作为开发依赖:
npm install @astryxdesign/core @astryxdesign/theme-neutral @stylexjs/stylex
npm install -D @astryxdesign/cli
npx @astryxdesign/cli init
init 步骤会把 Astryx 的组件索引写入你的 AGENTS.md 或 CLAUDE.md;如果没有 agent 会接触这个仓库,你可以跳过这一步。走简单路径的话,接下来按顺序引入三个样式表,并用主题 provider 包裹应用:
@import '@astryxdesign/core/reset.css';
@import '@astryxdesign/core/astryx.css';
@import '@astryxdesign/theme-neutral/theme.css';
按项目仓库自己的说法,这就是全部配置:三行 import、一个 provider,构建工具链无需任何改动。进阶路径则使用 @astryxdesign/build 从 TypeScript 与 StyleX 源码构建,该包附带了 Babel、PostCSS 和 Vite 插件,因此打包器只会为你实际引入的组件输出样式。Meta 在自家的参考应用中测得该路径产出的样式约为完整样式表的三分之一——这是他们在自己代码上的测量结果,而非普适规律。每个组件都从各自的子路径引入,而不是从包的根路径。
主题化:行为归系统,外观归 token
Astryx 把职责一刀切开。行为和无障碍能力留在库内;外观则交给 token 层,因此一份主题配置囊括了颜色、排版、圆角、间距和动效,改动其中一个值,所有读取该值的组件都会随之改变外观,而无需任何人打开组件代码。浅色和深色的取值并排放在同一个主题里,而不是分散在两份平行文件中,主题既可以在运行时切换,也可以编译成静态样式表。主题的能力还超出了 CSS 变量的范畴:它可以覆写单个组件及组件的局部构件,还能添加自定义变体。
项目自带七套现成主题,你是从某一套出发而不是从零开始:theme list 会列出可用主题,包括来自已安装集成的主题,而 theme add <slug> 会把你选中的那套作为可编辑的源码放进你的项目。这就是它的设计押注,一句话概括:设计师掌管一份配置文件,没人需要为了改外观去 fork 或包装组件。
渐进式定制路径
Astryx 的定制能力沿五个层级逐步升级:直接使用出厂组件、调整主题 token、附加 class name、叠加自己的 CSS,最后是把组件源码 swizzle 进你的仓库。每上一级,控制力更强,但所有权成本也更高。前四级都让你留在共享升级路径上;第五级则把该组件永久移出这条路径。
| 层级 | 你改动什么 | 你付出什么代价 |
|---|---|---|
| 直接使用 | 什么都不改 | 没有代价;升级免费 |
| 主题 token | 颜色、排版、圆角、间距、动效 | 一份由团队维护的配置文件 |
| Class name | 单实例的外观 | 级联层(cascade layer)的纪律性 |
| 自定义 CSS | 层级顺序允许的任何内容 | 选择器可能在升级时失效 |
| Swizzle | 组件本身 | 永久性的完整维护责任 |
Swizzle 是一道单向门。有些内部实现根本没有通过公共 API 暴露出来,比如私有 state、DOM 结构或你无法触达的事件监听器,弹出源码是唯一的通路;从那一刻起,你维护的是这个组件,而不是这个库。CLI 通过 astryx swizzle Button 和 astryx upgrade --apply 来弹出组件源码并运行版本 codemod:
npx @astryxdesign/cli swizzle Button
一次性执行时请使用带 scope 的形式:在 @astryxdesign/cli 尚未成为项目依赖之前,npm 会把裸写的 astryx 解析到一个无关的包上。采用 Astryx 之前最实用的做法是:挑出你最难对付的两三个组件,对照第五级评估一遍——如果你需要的定制必须触及内部实现,那就从第一天起就把维护这份源码的成本算进去。
样式互操作:xstyle、className 与 Tailwind
Astryx 组件同时接受用于 StyleX 覆写的带类型 xstyle prop 和普通的 className,因此它们可以与 Tailwind、CSS Modules 或原生样式表共存。同一个组件,三种写法:
import * as stylex from '@stylexjs/stylex';
import {Button} from '@astryxdesign/core/Button';
const styles = stylex.create({
save: {alignSelf: 'flex-end', marginBlockStart: 24},
});
// 1. As shipped
<Button label="Save" variant="primary" />;
// 2. Typed StyleX override, compiled at build time
<Button label="Save" variant="primary" xstyle={styles.save} />;
// 3. Plain className, no compiler involved
<Button label="Save" variant="primary" className="ml-auto mt-6" />;
在预编译路径下,第三种方式不需要任何额外的工具链:StyleX 只是 Astryx 编写自身样式的方式,而不是你必须配置的东西。但有一个前提条件。Astryx 会把样式表加载到级联层中,reset 进入 @layer reset,组件样式进入 @layer astryx-base,而级联层并不受特异性(specificity)支配:任何未归入层的样式,或放在更晚声明的层中的样式,无论如何都会胜出。因此,已经带有全局 CSS、旧版 reset 或 Tailwind 的项目必须自行设定层级顺序,并有意识地把每一份样式表都放进某个层里。
Astryx 对比 shadcn/ui 与 Base UI:区别在哪?
Meta 在发布文章中把 Astryx 置于它所指出的两种结局之间:采用某家大公司的设计系统,你就会继承它的品牌调性;而拼凑复制粘贴来的组件,你获得了自由,却放弃了共享的一致性、上游修复和升级路径,无障碍能力则默认落到你团队头上。这是 Meta 为自家产品做的论证,值得对照替代方案自身的说法来检验一番。shadcn/ui 对自身的描述恰好反过来:它不是一个你安装的库,而是一种构建你自己组件库的方式,把组件代码直接交给你去编辑。拥有代码本身就是特性,而不是副作用——我们在团队为何转向 shadcn/ui 的分析中对此有更深入的探讨。Base UI 提供的是无样式(headless)的 React 组件和 hooks,本身不带任何 CSS,所以最终的外观完全由你决定。
把这些当作约束条件而非优劣判决来读:Base UI 给你符合无障碍标准的行为,不带任何审美主张;shadcn/ui 给你源码,以及随之而来的维护责任;Astryx 给你一套主题化的系统,同时仍允许你按组件粒度弹出。Astryx 的第五级最终抵达的是与 shadcn/ui 相同的位置,只是走了另一条路——一次一个组件,且只在你主动选择时才发生。
需要注意的地方也很直白。它是 0.x 版本的公测产品,没有稳定版本线;它以 React 19 为准入门槛;而且它是单一厂商项目——发布后的讨论提出了治理和长期维护方面的疑问,目前没有任何公开信息给出答案。公测期的变动并非假想:0.6.0 版本会破坏所有直接调用 useStepperContext 的代码,该 hook 移除了紧凑布局相关字段,并把 StepperContextValue 收窄为过渡历史和步骤注册。另一方面,社区页面提到有官方 Discord,且 GitHub issues 每周分流处理。
现在谁该试试 Astryx,谁该再等等?
如果你正在 React 19 上启动一个全新的内部工具或仪表盘,希望获得符合无障碍标准的组件而不必自己设计,并且团队里有位设计师宁愿掌管 token 也不愿审阅 CSS pull request,那就现在试。如果你的 React 版本低于 19,或者你维护的是面向公众的产品——一次 0.x 小版本更新改动 context 结构就会让你付出一个发布周期的代价,又或者单一厂商治理是你目前无法答复的采购问题,那就先等等。一条实用的中间路线是拿现有应用的某一条路由做试点:使用预编译样式表、显式声明 @layer 顺序,并用那些你本来也得自己手写的组件搭出一个页面。
真正需要评估的不是组件数量,而是你的设计需求会把你推到定制阶梯的哪一级——因为那才是你一年后仍在为之付费的东西。挑出产品上绝不能妥协的那两个组件,对每个执行 npx @astryxdesign/cli component <Name>,看看在被迫弹出源码之前,token 和 className 能不能把你送到目的地。
常见问题
Astryx 和 StyleX 有什么区别?
StyleX 是 Meta 的构建时 CSS-in-JS 编译器,能把样式对象转换为原子化、无冲突的 CSS。Astryx 是用它编写样式的 React 组件设计系统。Astryx 会把 @stylexjs/stylex 作为 peer dependency 安装,但使用预编译样式表并不需要任何构建插件、PostCSS 或 Babel 配置。只有从源码构建时才会引入 @astryxdesign/build 中的 StyleX 插件。
Astryx 能配合 Next.js、Vite 或纯 CDN 方式使用吗?
可以。@astryxdesign/core 的 README 记录了 Next.js、Tailwind、Vite 和 CDN 的配置方式。在预编译路径下,你引入 reset、组件样式表和一份主题样式表,然后用主题 provider 包裹应用,完全不涉及打包器插件。而改为从 TypeScript 与 StyleX 源码构建,则需要 @astryxdesign/build 中提供的 Babel、PostCSS 或 Vite 插件。
使用这个库必须用 Astryx CLI 吗?
不必。仅靠已安装的包,组件和预编译 CSS 就能正常工作,CLI 只是开发依赖。你需要它来执行 theme list 和 theme add、查看完整组件文档、使用模板、运行升级 codemod 以及进行 swizzle。执行 astryx init 会把 Astryx 组件索引写入 AGENTS.md 或 CLAUDE.md,这只在有 AI agent 参与仓库工作时才有意义。
Astryx 的图表组件可以用于生产环境了吗?
还不行。Vega 封装包 @astryxdesign/vega 和基于 d3 的图表库 @astryxdesign/charts 只在 canary dist-tag 下向 npm 发布真正的构建产物;它们的 latest tag 指向一个占位发布,npm 会提示你不要安装。实验性的 @astryxdesign/lab 包(新组件在正式进入 core 之前会先落地于此)也采用同样的发布方式。因此,图表功能的成熟度还落后于本已处于 0.x 公测阶段的 core 包,需要为其单独准备回退方案。
Truly understand users experience
See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data.
Star on GitHub12k