推出 Catalyst:现代 React UI 套件

Adam Wathan

今天就是这一天 — 我们刚刚发布了 Catalyst 的第一个开发预览版,正好赶上您的假日黑客编程时光。

Catalyst 包含的组件概览

Catalyst 是我们第一个完全组件化、功能齐全的应用程序 UI 套件 — 真实的 React 组件,具有经过深思熟虑设计的 API,这些 API 相互构建,形成一个真实的组件架构,就像我们在真实应用程序中会做的那样。

查看在线演示,阅读文档,如果您是 Tailwind UI 全访问客户,今天就下载它并在新项目中尝试使用。

Catalyst 目前处于开发预览阶段,还有很多内容即将推出,但我们今天就发布它,这样您可以立即开始使用它,而我们继续构建新组件并找到让它变得更好的方法。


您的组件,而不是我们的

在开发 Catalyst 时,我们致力于构建一个明天的 Stripe 或 Linear 都会乐于使用来构建其产品的 UI 套件 — 那些对设计有执着追求的团队,他们想要拥有自己的 UI 组件,而永远不会选择现成的库。

所以它不是您安装的依赖项,而是您下载源代码并将组件复制到您自己的项目中,它们成为您自己组件系统的起点:

想要更改按钮的边框圆角?只需打开 button.tsx 并更改一些类。您不需要开一个 GitHub issue 并试图说服我们暴露一个新的配置选项。

Catalyst 是一个"消失的 UI 套件" — 安装它六个月后,您应该几乎忘记不是您自己构建的原始组件。


设计在细节中

在这样的项目中,获得正确的视觉风格是很难的。我们带着几个目标进入了这个项目:

  • 具有竞争力 — 我们希望设计出能够与当今网络上一些最漂亮的界面媲美的东西。
  • 永不过时 — 我们不想设计出在 6 个月后看起来会过时的东西,因为它过于依赖特定的趋势。
  • 高效 — 无论我们设计的是什么,都需要让真实用户感到快速和高效,而不仅仅是在 Dribbble 上看起来很棒。

这需要大量的工作,并且有很多权衡需要平衡,但我真的很喜欢我们最终的结果:

为了具有竞争力,我们在很多细节上进行了投资,比如在下拉菜单上使用微妙的背景模糊,完善阴影和边框在表单控件上的相互融合方式,以及在对话框和切换开关等事物中对动画的深思熟虑使用。

为了永不过时,我们试图在平面设计和拟物设计之间找到正确的平衡,具有足够的深度提示,即使趋势在任一方向上发生了一些变化,我们的组件也会看起来很棒。

我们还从浏览器中汲取灵感,使用无偏见的蓝色焦点环,以避免选择可能很快看起来过时的处理方式。

为了高效,我们仔细工作,确保仍有足够的空白,但 UI 仍然足够密集,可以在屏幕上容纳大量信息。

我们还限制了过渡和动画的使用,仅在感觉重要的地方使用,即使在那时也尽量保持快速,这样您永远不会觉得在等待 UI。

Catalyst 还支持完整的暗模式,使用 Catalyst 组件构建的任何内容都会自动适应明暗模式。

这并不明显,但我们必须更改大量细节,以使事物在暗模式下看起来最好,比如调整阴影,将外环更改为内环以模仿光照变化等等。


模仿 HTML

我们花了很多时间研究组件 API,努力使其非常容易立即使用,而不影响灵活性。

UI 库通常使用这样的 API:

JSX
function Example() {  return (    <TextField      name="product_name"      label="Product name"      description="Use the name you'd like people to see in their cart."    />  );}

但是,当所有的 props 都在同一个组件上时,开始很难做一些事情,比如仅向 <input> 元素本身添加一个类。

最终,这导致我们采用了与 HTML 非常相似的 API,在这种 API 中,单个组件很少渲染多个元素。

例如,使用 Catalyst 创建一个文本字段看起来像这样:

import { Description, Field, Label } from "@/components/fieldset";import { Input } from "@/components/input";function Example() {  return (    <Field>      <Label>Product name</Label>      <Description>Use the name you'd like people to see in their cart.</Description>      <Input name="product_name" />    </Field>  );}

通过保持这种可组合性,可以很容易地做一些事情,比如限制输入的宽度,而不限制任何其他元素的宽度:

import { Description, Field, Label } from "@/components/fieldset";import { Input } from "@/components/input";function Example() {  return (    <Field>      <Label>Product name</Label>      <Description>Use the name you'd like people to see in their cart.</Description>      <Input name="product_name" className="max-w-sm" />    </Field>  );}

这也使得将描述移到输入框下方变得容易,而不是上方:

import { Description, Field, Label } from '@/components/fieldset'import { Input } from '@/components/input'function Example() {  return (    <Field>      <Label>Product name</Label>      <Description>Use the name you'd like people to see in their cart.</Description>      <Input name="product_name" className="max-w-sm" />      <Description>Use the name you'd like people to see in their cart.</Description>    </Field>  )}

我们花了很多时间试验,找出使这些 API 工作的正确方法,特别是在向正确的子元素添加布局样式等细节方面,但回报是值得的,这些组件真的很愉快使用。


由下一代 Headless UI 提供支持

我们在 2020 年夏天发布了第一个版本的 Headless UI,但自从上一个重要功能发布以来已经一年多了,因为我们一直专注于 Tailwind CSS 本身的工作。

Catalyst 是我们再次深入研究 Headless UI 的完美借口,我们很快发现了许多改进项目的方法,以简化 Catalyst 本身的代码。

我们刚刚发布了 Headless UI v2.0.0-alpha.1,其中包含大量新内容:

  • 内置锚点定位 — 使用 Floating UI,像 MenuListbox 等组件现在可以自动定位其弹出窗口,使其锚定到其触发器,并根据需要适应视口的变化。
  • 无头复选框组件 — 我们添加了一个无头 Checkbox 组件,以补充我们现有的 RadioGroup 组件,使构建完全自定义的复选框控件变得容易。
  • HTML 表单组件 — 我们添加了 InputSelectTextareaLabelDescriptionFieldsetLegend 组件,这些组件处理所有的 ID 生成和 aria-* 属性映射,您需要将表单字段连接在一起。
  • 改进的悬停和焦点可见检测 — 使用来自出色的 React Aria 库的钩子,Headless UI 现在向您的控件添加了更智能的 data-hoverdata-focus 属性,这些属性在不同设备上的行为比本机伪类更一致。
  • 组合框列表虚拟化 — 下一版本的 Headless UI 现在可以处理巨大的组合框选项列表,而不会出现性能问题。

...还有许多其他改进即将推出,包括日期选择器、工具提示等。

这些改进目前仅适用于 React,在这个早期 alpha 阶段,但我们计划在标记 v2.0 之前将所有这些改进带到 Vue。

我们很快就会为这些内容发布文档,但即使这意味着在假期前几天发布 Headless UI 文档,我们也无法抗拒在假期前发布 Catalyst。


试试看

Catalyst 是所有 Tailwind UI 全访问 客户的免费更新,您可以下载它并开始使用这个第一个版本。

为了让我们今天发布的所有内容都恰到好处,投入的工作比您想象的要多得多,但我们渴望得到反馈和改进的方法,所以用它构建一些东西,并告诉我们您的想法。

我们将在假期期间休息几周,但在新的一年里,我们将立即回到 Catalyst,致力于新的组件,如应用程序布局、组合框、命令面板、工具提示等。

Get all of our updates directly to your inbox.
Sign up for our newsletter.