Transcript

00:00:00别再用 Radix 组件了,是时候换成 Base UI 了,事实上如果你是 shadcn 的粉丝,
00:00:06现在已经可以选择切换过去了。如果你还没听说过 Base UI,它其实
00:00:10是由 Radix、Floating UI 和 Material UI 的原班人马打造的无样式 (headless) UI 库。
00:00:15它提供了组件的功能性和可访问性,而设计部分依然由你掌控,
00:00:20这在当下尤为重要,因为 LLM 在处理复杂的边缘情况和可访问性需求时表现依然一般。但正如我所说,
00:00:24Radix 本质上也是这样的库,那为什么还需要一个新的呢?
00:00:30让我们直接开始,让我为你展示它们之间的核心区别。
00:00:35我先带大家快速过一下 Base UI 的文档,看看左侧这些
00:00:44组件,你可以看到它们几乎涵盖了组件库中所需的所有类型,
00:00:48甚至包括一些像组合框 (Combo Box) 这样在 Radix 中找不到的高级组件。
00:00:52你会发现所有组件都有精美的示例,演示了如何使用
00:00:57CSS Modules 来设置样式,你甚至可以根据需要切换到 Tailwind 示例,
00:01:01文档做得很棒,但我们今天不是来对比文档的,所以让我们直接进入第一个关键区别,
00:01:06也是你可能会最常听到的:Base UI 正在积极维护中,
00:01:10而 Radix 则有点像处于“僵尸状态”。我是说,看看 GitHub 的贡献图,
00:01:15你会发现 Base UI 正在持续增长,而 Radix 似乎只是偶尔修补一下,
00:01:20当我们查看上个月关闭的 PR 和 Issue 时,情况就更明显了。
00:01:25Base UI 关闭了 58 个 Issue 并合并了 154 个 PR,
00:01:29而 Radix 却是一个都没有。简单来说,Radix 发生的事就是 WorkOS 收购了它背后的公司,
00:01:36但并没有真正对 Radix 进行投入。所以 Radix 团队大部分成员都离开了,这就是目前的现状。
00:01:42Radix 的联合创始人甚至说过,除非那是最后的选择,否则他不会再用 Radix,
00:01:47而他现在就在开发 Base UI。所以,重点是确保你的应用和依赖项是活跃维护的,
00:01:53以免将来遇到无法修复的 Bug 时让你头疼。更好的是,
00:01:58Base UI 的设计初衷就是与 Radix 保持相似,所以迁移起来并不难,
00:02:02但这并不意味着他们没能加入一些改进。其中一个我最喜欢的改进
00:02:08是他们处理 Radix 中那个 “as child” 属性的方式。如果你没用过,
00:02:13我现在这里有一个 Radix 的 Select 组件,如果我想用自定义组件
00:02:17作为 Select 的触发器 (Trigger),如果我只是简单地用 Trigger 组件包裹它,
00:02:22你会发现得到的是一个包裹组件,以及里面那个写着“订阅”的按钮(顺便说一下,你应该点点那个按钮)。
00:02:27但如果我想让这个“订阅”按钮直接充当 Select 的触发器,
00:02:31在 Radix 中,我只需要给 Trigger 添加 “asChild” 属性,
00:02:36这就在告诉 Radix 将 Trigger 的所有属性和功能合并到
00:02:41它的子组件上。你可以看到,这里的类名已经和按钮合并了,
00:02:46在这种情况下甚至覆盖了它。如果我删掉那个属性并保存,
00:02:50你会看到我们现在只有一个按钮,但在功能上它充当了 Select 的触发器。
00:02:55这是一个非常方便的功能,但常见的槽点是它不够直观,
00:03:00我承认,有时在快速浏览代码时,我会漏掉这个属性,从而找不到问题的根源。
00:03:04如果切换到 Base UI,你会发现可以实现完全相同的功能,
00:03:09我这里也有一个作为 Select 触发器的按钮,但看看代码,
00:03:13Base UI 使用的是 “render” 属性,而不是 “asChild”。
00:03:18在 “render” 属性中,你可以指定想要渲染出来的组件作为你的触发器。
00:03:24虽然变化微小,但我认为它让意图变得更加明确:它就是字面意思上的“渲染”这个组件。
00:03:29这样你就不必寻找子组件,再去找那个 “asChild” 属性。就像我说的,
00:03:34只是个小变动,但非常实用。而且这还不是 “render” 属性最强大的地方,
00:03:39当我们构建 Switch 组件时,我们可以给 “render” 属性传递一个函数,
00:03:43从而访问组件当前状态的属性。在这个例子中,即 Switch Thumb,
00:03:48这让我们可以:A,选择要应用传递属性的组件;
00:03:52B,根据组件状态执行一些自定义渲染或样式逻辑。
00:03:56比如在 Switch Thumb 中,我们可以检查它是 checked、dirty、disabled 还是 filled 等等。
00:04:01在这个案例里,我们只是简单地检查它是否被选中 (checked),
00:04:05如果是,就渲染一个不同的图标。甚至还有一个 Hook 允许你
00:04:10将这种 “render” 模式集成到自定义组件中,不过这有点进阶了,
00:04:14但希望你能看到,任何自定义需求,Base UI 都能胜任。
00:04:18回到 Select 组件,下一个区别是 Base UI 支持部分组件由数据驱动。
00:04:22我们以这里的 Select 为例,目前是 Radix 的代码,
00:04:27我们有一个包含 label 和 value 的数组,为了把这些值放入 Select,
00:04:31在 Radix 中唯一要做的是遍历这个苹果数组,然后渲染出 Select Item,
00:04:35这样就能把值添加进去。如果我们看 Base UI 是怎么做的,
00:04:40你会发现非常相似,我们同样有 label 和 value 数组,依然在进行遍历和渲染,
00:04:44但在另一个地方也有不同:在 Select Root 上,我们传入了这个数组。
00:04:49这会产生一个微妙的影响:组件在渲染前就感知到了数据,
00:04:54这意味着性能会稍好一些,尤其是在服务器端渲染 (SSR) 时。
00:04:59但我认为这里还有一个可以改进的地方,目前我把数组作为 “items” 属性传递,
00:05:03但下面还要再遍历一次数组。我认为他们应该借鉴 React Aria,
00:05:08那是另一个无样式库。你看,我们有动物数组,直接作为 “items” 传进去,
00:05:13然后它的子元素只需要使用一个函数。它会自动感知父元素传递的所有项,
00:05:17这样就不必在两个地方使用同一个数组,而父元素充当了数据提供者。
00:05:22这确实是还有提升空间的地方。回到 Select 组件,我想展示另一个区别,
00:05:26这是 Select 组件特有的。虽然 “render” 属性和数据驱动方法在大部分组件中都有,
00:05:32但这个区别专属于 Select:它支持多选 (multi-select)。
00:05:36这是 Radix 中一直非常遗憾缺失的功能。在 Base UI 中,你只需在 Select Root
00:05:41添加一个 “multiple” 属性即可,它就变成了一个多选下拉框,非常简单。
00:05:45更进一步,Base UI 还有一些 Radix 缺失的组件,比如 Combo Box 和 Auto Complete,
00:05:50这就是积极维护带来的好处,他们可以快速响应用户的需求。
00:05:55接下来还有两个我想展示的差异,我们将切换到 Checkbox 组件,
00:05:59因为看 Select 已经看累了。第一个差异是关于样式的,
00:06:03Base UI 提供了一个我认为非常酷的样式选项。目前我在用 Tailwind,
00:06:08你可以使用传统的方法,比如普通 CSS、CSS Modules 等等,
00:06:13但如果你使用 Tailwind,通常会通过 Data Attribute 来根据状态设置样式,
00:06:17比如 “data-checked”,如果被选中,就应用 primary 背景色。
00:06:22这会导致 Tailwind 的类名字符串非常长,有时会成为一个问题。
00:06:27Base UI 提供的另一个选择是:你可以将函数作为类名。这让你能访问组件的状态,
00:06:33在这个 Checkbox 例子中,我根据状态是否为 checked 或 disabled 来应用样式。
00:06:38我用一个简单的条件判断来实现,我认为这种方式在快速浏览代码时
00:06:41更清晰,能一眼看出 checked 和 disabled 的样式来源,
00:06:45而不是在长长的一行里去翻找那些 Data Attribute。如果你使用的是 Vanilla CSS,
00:06:50这种方式会更有帮助。它也能很好地配合另一个我喜欢的库:Tailwind Variants。
00:06:55你可以看到,我只需把状态传递给 checkbox 函数,在 Tailwind Variant 里
00:06:59定义基础样式和变体样式,然后通过简单的逻辑:如果是 checked 则应用这些样式,
00:07:04如果是 disabled 则应用那些。我觉得这比用 Data Attribute 清晰得多,
00:07:08当然这取决于你的个人习惯。Base UI 能提供这么多选择是非常棒的。
00:07:13我还要补充一点,把函数作为类名是我最初在使用 React Aria 时爱上的,
00:07:17所以在我看来,React Aria 学习曲线比较陡,而 Radix 非常简单,
00:07:22Base UI 则恰好取了两者的中间地带,吸收了它们的优点,打造出了这个终极的无样式库。
00:07:26以上就是我想在这期视频中分享的关键差异,但其实还有很多,比如对 React Hook Form
00:07:31和 TanStack Form 的良好支持,内置动画支持让组件动画处理更轻松,
00:07:35甚至还有输入擦除 (Input Scrubbing)、嵌套对话框以及悬停触发菜单等功能。
00:07:40我相信如果你有合理的需求,积极维护的团队会在 GitHub 上回应你。顺便提一下,
00:07:45我并不建议立刻把现有的 Radix 项目迁移到 Base UI,因为 Radix 还没到完全不能用的地步。
00:07:49但如果是新项目,我肯定会选 Base UI。如果我需要 Combo Box 或 Auto Complete 等功能,
00:07:53我也会考虑迁移。在评论区告诉我你对 Base UI 的看法,
00:07:58顺便订阅一下,我们下期视频再见。
00:08:02clearer than using those data attributes but it's definitely up to your opinion and what you're
00:08:06comfortable with using it's just super nice that base ui gives us all of these choices i'll also
00:08:11add that using a function as a class name was something i first fell in love with from react
00:08:14area so it really seems to me like we have react area over here which does have a steeper learning
00:08:19curve and radix which is quite simple and base ui has sort of met in the middle and taken the
00:08:23features that i like about both of them and created me the ultimate headless library now that's all of
00:08:28the key differences that i wanted to go over in this video but there is still loads more like base ui has
00:08:33great support for react hook form and tan stack form it has animation support to make it a nice
00:08:38and easy process to actually animate your components and it even has features like input scrubbing
00:08:42nested dialogues and triggering menus on hover and i'm sure if you have a reasonable request they'd
00:08:47actually respond to it over on the github as it is actively maintained it is also worth saying though
00:08:52that i probably wouldn't jump to migrating my radix app over to base ui straight away as i don't think
00:08:57radix is completely broken if i'm starting a new project i definitely use base ui now and if i wanted
00:09:02a feature like a combo box or an autocomplete i'd also consider migrating my application let me know
00:09:07what you think of base ui in the comments though while you're down there subscribe and as always
00:09:11see you in the next one

Key Takeaway

Base UI 作为 Radix 的继任者,通过更活跃的维护、更直观的 API 设计和更丰富的功能组件,成为了现代 Web 开发中构建无样式组件库的首选工具。

Highlights

Base UI 是由 Radix、Floating UI 和 MUI 原班人马打造的全新无样式 (headless) UI 库。

Base UI 弥补了 Radix 维护停滞的现状,提供了更活跃的 GitHub 贡献和长期支持。

引入了 "render" 属性代替 Radix 的 "asChild",提升了组件渲染的语义清晰度与灵活性。

支持通过函数作为 className 进行状态化样式定制,避免了冗长的 Tailwind 类名字符串。

提供了 Radix 缺失的高级组件,如多选下拉框 (Multi-select)、组合框 (Combo Box) 和自动补全。

在数据处理上采用数据驱动模式,有助于提升服务端渲染 (SSR) 的性能表现。

集成了对 React Hook Form 的良好支持以及内置动画处理,降低了复杂交互的开发成本。

Timeline

Base UI 简介与背景

视频开篇介绍了 Base UI 这一新兴的无样式 UI 库,并建议开发者从 Radix 转向它。Base UI 的核心开发团队由来自 Radix、Floating UI 和 Material UI 的专家组成,保证了库的专业性。它专注于提供组件的功能性和可访问性 (Accessibility),将设计权完全交给开发者。这在当前 AI 生成代码的时代尤为重要,因为 LLM 往往难以处理复杂的可访问性需求。作者强调,虽然 Radix 曾经是行业标准,但 Base UI 的出现是为了解决现有库的局限性。

维护状态对比:Radix vs Base UI

这一章节通过 GitHub 贡献数据详细对比了两个库的活跃度。Radix 由于被 WorkOS 收购后缺乏投入,核心团队流失,目前处于几乎停止更新的“僵尸状态”。相比之下,Base UI 的 Issue 关闭量和 PR 合并量远超 Radix,显示出极高的社区活力。Base UI 的创始人也是 Radix 的原作者,他明确表示除非别无选择否则不再使用旧库。对于开发者而言,选择一个持续维护的库能有效规避未来可能出现的未修复 Bug。Base UI 的 API 设计在保持与 Radix 相似的同时,针对过往痛点进行了深度改进。

渲染机制的革新:从 asChild 到 render

作者通过代码演示了 Base UI 如何优化自定义组件的触发机制。在 Radix 中,开发者需要使用不太直观的 "asChild" 属性来合并属性,这在快速阅读代码时容易被忽略。Base UI 引入了 "render" 属性,不仅在语义上更清晰,还支持传入函数来访问组件的实时状态。这种函数式渲染允许开发者根据 checked 或 disabled 等状态动态渲染不同的图标或内容。此外,Base UI 还提供了专门的 Hook,方便将这种渲染模式集成到更复杂的自定义组件中。这些改进极大增强了 headless 组件的灵活性和可维护性。

数据驱动与多选功能增强

本节重点讨论了 Select 等组件在数据处理上的差异。Base UI 支持在 Root 层面直接传入数据数组,使组件在渲染前就能感知数据,从而优化了 SSR 性能。尽管作者认为在 API 简洁度上仍有提升空间,但相比 Radix 已经是一大进步。最令人兴奋的更新是 Base UI 内置支持多选 (Multi-select) 模式,这解决了 Radix 长期以来的一大功能缺失。同时,库中还包含了 Combo Box 和 Auto Complete 等高级组件,满足了更复杂的业务需求。积极的团队响应确保了这些用户急需的功能能被快速实现并发布。

样式定制与未来选择建议

在样式处理上,Base UI 允许将函数作为 className,使 Tailwind 开发者能摆脱长串的 Data Attribute 逻辑。这种方式让样式与组件状态(如选中、禁用)的关联一目了然,且能与 Tailwind Variants 等工具完美配合。作者总结道,Base UI 成功融合了 React Aria 的强大功能与 Radix 的简洁性,是目前的“终极无样式库”。虽然不建议立即将所有旧项目迁移,但对于新项目或需要复杂组件的场景,Base UI 无疑是更好的选择。最后,视频提到了它对表单库和动画的内置支持,进一步证明了其在生产环境中的竞争力。

Community Posts

View all posts