这周我们忙着收尾一系列项目,但一切终于尘埃落定,所以感觉是时候再更新一下了。
¥It's been a busy week wrapping up a bunch of projects we've been working on, but everything is finally out the door so it feels like a good time for another update.
自我上一篇文章发布以来,我们又对另一个 226 GitHub issues and pull requests 问题进行了分类并解决了它,现在我们整个组织内的未解决问题/PR 数量终于首次低于 50 个。所以请不要再找 bug 了,我只想用 Tailwind CSS 设计和构建一些漂亮的东西。
¥We triaged and resolved another 226 GitHub issues and pull requests since my last post, and we're finally at under 50 open issues/PRs across our entire organization for the first time ever. So please stop finding bugs I just want to design and build beautiful stuff with Tailwind CSS for a while.
说到精彩的功能,以下是过去几周发布的内容!
¥Speaking of beautiful stuff, here's what shipped over the last couple of weeks!
亮点:你的全新个人网站(Spotlight: Your new personal website)
¥Spotlight: Your new personal website
几天前,我们发布了 Spotlight,这是一款专为 Tailwind UI 设计的精美全新个人网站模板。
¥A couple of days ago we released Spotlight, a stunning new personal website template we designed for Tailwind UI.

与我们的其他模板一样,它是使用 Next.js 构建的,而这次我们使用 MDX 来支持所有 Markdown 驱动的内容,例如博客部分。
¥Like our other templates, it's built with Next.js, and this time we're using MDX to power all of the markdown-driven stuff like the blog section.
设计这个模板是一个非常有趣且引人入胜的挑战 - 我们希望设计出一个既美观又鼓舞人心的东西,但又不至于太刻板,几乎适合所有人。我们最终确定了一个非常简约的设计,其个性体现在一些小细节上,例如旋转的图片、链接的颜色提示,以及在顶部导航等位置通过阴影和分层带来的微妙深度。
¥Designing this template was a pretty fun and interesting challenge — we wanted to come up with something that was really beautiful and inspiring, but that was also unopinionated enough to feel like a good fit for almost anyone. We landed on a pretty minimalist design that gets its personality from little touches like rotated images, hints of color for links, and some subtle depth from shadows and layering in places like the top navigation.

一如既往,我建议你查看 the live preview 以获得完整的体验 - 尤其要注意滚动浏览主页时头像和导航的运作方式,在实际使用网站时,这简直是“厨师之吻”。
¥As always, I recommend checking out the live preview for the full experience — especially pay attention to the way the avatar and navigation works on the home page as you scroll, it's very chef's kiss when you're playing with the real site.
我们尝试以构建我们个人网站的方式来构建这个网站,因此它包含一个专门的博客、一个列出你参与过的一些最喜欢的项目的页面、一个供你链接到你发表过的会议演讲等内容的区域,以及一个列出你所有最喜欢的工具和装备的 "uses" page。
¥We tried to structure the site the way we'd structure our own personal sites, so it includes a dedicated blog, a page for you to list some of your favorite projects you've worked on, an area for you to link to things like conference talks you've given, and a "uses" page to list all of your favorite tools and gear.
如果你拥有 Tailwind UI all-access 许可证,那么你已经可以访问此模板了!如果你还没有,请考虑一下 - 这是支持我们开发 Tailwind CSS、Headless UI 和 Heroicons 等开源项目的最佳方式。
¥If you've got a Tailwind UI all-access license then you've already got access to this template! And if you don't, consider it — it's the best way to support our work on open-source projects like Tailwind CSS, Headless UI, and Heroicons.
Heroicons v2.0
去年我们发布了 Heroicons v1.0。上周我们发布了 Heroicons v2.0,这是一套全新的图标集,由 Steve 耗时约一年从零开始绘制。
¥Last year we released Heroicons v1.0. Well last week we released Heroicons v2.0, which is a brand new icon set, illustrated from scratch that Steve has been working on for about a year.

它包含 280 个以三种不同风格绘制的图标:
¥It includes 280 icons drawn in three distinct styles:
-
轮廓 - 线条图标,描边为 1.5px,绘制在 24px 的视图框中。
¥Outline — line icons with a 1.5px stroke, drawn in a 24px view box.
-
Solid — 带有填充形状的实心图标,在 24px 的视图框中绘制。
¥Solid — solid icons with filled shapes, drawn in a 24px view box.
-
迷你图标 - 带有填充形状的实心图标,绘制在 20px 的视图框中。
¥Mini — solid icons with filled shapes, drawn in a 20px view box.
与 v1 版本最大的区别在于,轮廓集使用了更细的描边,这在当今看来更具现代感和时尚感,而且图标的视觉风格也更加俏皮。
¥The biggest differences from v1 are that the outline set uses a thinner stroke, which feels a bit more modern and fashionable these days, and visually the icons are a bit more playful in style.
尽管名称中带有 "v2",但最好将 Heroicons v2 视为终端 2 而不是 OpenSSL 2 - 我们觉得它们代表了我们最好的作品,但它是一个新的图标集,严格来说不是原始图标集的升级。不要像处理真正的应用依赖那样,感到升级现有项目的压力,但如果你想迁移,check out the release notes 可以满足你切换所需的一切。
¥Even though these have "v2" in the name, it's better to think of Heroicons v2 more like Terminator 2 than OpenSSL 2 — we feel like they represent our best work but it's a new icon set, not strictly an upgrade from the original icon set. Don't feel pressured to upgrade existing projects like you would with a real application dependency, but if you want to migrate, check out the release notes for everything you need to switch.
要探索所有新图标,请访问我们随新图标集一起推出的 Totally redesigned Heroicons website。
¥To explore all of the new icons, visit the totally redesigned Heroicons website we launched with the new set.
Headless UI v1.7
本周早些时候,我们发布了 Headless UI 的新版本,这是我们的 React 和 Vue 无样式 UI 组件库。
¥Earlier this week we tagged a new release of Headless UI, our React and Vue libraries of unstyled UI components.

Headless UI v1.7 不仅修复了大量常见的错误并进行了改进,还包含一些非常实用的新功能!
¥Headless UI v1.7 includes the usual slew of bug fixes and improvements, but also some really useful new features!
添加了 "by" 属性,用于控制对象比较(Added "by" prop for controlling object comparisons)
¥Added "by" prop for controlling object comparisons
我们为 Listbox
、Combobox
和 RadioGroup
组件添加了新的 by
属性,这使得将对象绑定为表单值变得轻松许多。
¥We've added a new by
prop to the Listbox
, Combobox
, and RadioGroup
components that make it a lot less cumbersome to bind an object as the form value.
import { Listbox } from "@headlessui/react";const departments = [ { id: 1, name: "Marketing", contact: "Durward Reynolds" }, { id: 2, name: "HR", contact: "Kenton Towne" }, { id: 3, name: "Sales", contact: "Therese Wunsch" }, { id: 4, name: "Finance", contact: "Benedict Kessler" }, { id: 5, name: "Customer service", contact: "Katelyn Rohan" },];function DepartmentPicker({ selectedDepartment, onChange }) { return ( <Listbox value={selectedDepartment} by="id" onChange={onChange}> <Listbox.Button>{selectedDepartment.name}</Listbox.Button> <Listbox.Options> {departments.map((department) => ( <Listbox.Option key={department.id} value={department}> {department.name} </Listbox.Option> ))} </Listbox.Options> </Listbox> );}
这使得从组件外部获取值变得容易得多,并且省去了你绑定 id
或类似组件并在需要时自己进行大量查找以找到完整对象的麻烦。
¥This makes it a lot easier for the value to come from outside the component, and saves you having to just bind the id
or similar and do a bunch of lookups yourself to find the full object when needed.
查看每个组件的更新后的 "Binding objects as values" documentation 以了解更多详细信息。
¥Check out the updated "Binding objects as values" documentation for each component for some more detail.
将表单控件用作非受控组件(Use form controls as uncontrolled components)
¥Use form controls as uncontrolled components
Listbox
、Combobox
和 RadioGroup
组件现在允许你选择性地传递 defaultValue
而不是 value
,从而允许你将它们用作不受控制的组件。
¥The Listbox
, Combobox
, and RadioGroup
components now let you optionally pass a defaultValue
instead of a value
, allowing you to use them as an uncontrolled component.
import { Listbox } from "@headlessui/react";const people = [ { id: 1, name: "Durward Reynolds" }, { id: 2, name: "Kenton Towne" }, { id: 3, name: "Therese Wunsch" }, { id: 4, name: "Benedict Kessler" }, { id: 5, name: "Katelyn Rohan" },];function Example() { return ( <form action="/projects/1/assignee" method="post"> <Listbox name="assignee" defaultValue={people[0]}> <Listbox.Button>{({ value }) => value.name}</Listbox.Button> <Listbox.Options> {people.map((person) => ( <Listbox.Option key={person.id} value={person}> {person.name} </Listbox.Option> ))} </Listbox.Options> </Listbox> <button>Submit</button> </form> );}
当你使用传统的 HTML 表单或表单 API(使用 FormData
收集其状态,而不是使用 React 状态进行跟踪)时,这可以简化你的代码。
¥This can simplify your code when using traditional HTML forms or form APIs that collect their state using FormData
instead of tracking it using React state.
查看每个组件的 "Using as an uncontrolled component" documentation 了解更多示例。
¥Check out the "Using as an uncontrolled component" documentation for each component to see some more examples.
仅 CSS 状态样式的数据属性(Data attributes for CSS-only state styling)
¥Data attributes for CSS-only state styling
过去,我们总是需要通过检查通过 render prop 传递的参数,并有条件地渲染任何有意义的类或内容,来设置 Headless UI 组件的不同状态的样式。当你只是尝试调整背景颜色或进行其他一些纯 CSS 更改时,这可能会感觉像是一大堆样板代码。
¥Historically, you've always had to style the different states of a Headless UI component by inspecting arguments passed through a render prop and conditionally rendering whatever classes or content made sense. This could feel like a lot of boilerplate when just trying to tweak a background color or make some other CSS-only change.
在 Headless UI v1.7 中,我们为渲染的 HTML 添加了 data-headlessui-state
属性,其中包含有关当前状态的信息,因此你只需使用 CSS 即可定位它。
¥In Headless UI v1.7, we've added a data-headlessui-state
attribute to the rendered HTML that includes information about the current state so you can target it with just CSS.
我们还发布了一款全新的 @headlessui/tailwindcss 插件,它为这些状态提供了多种变体,只需使用 Tailwind CSS 类即可轻松设置样式:
¥We've also released a new @headlessui/tailwindcss plugin that gives you variants for these states so they are super easy to style with just Tailwind CSS classes:
<Listbox.Option key={person.id} value={person} className="ui-active:bg-blue-500 ui-active:text-white ui-not-active:bg-white ui-not-active:text-black"> <CheckIcon className="ui-selected:block hidden" /> {person.name}</Listbox.Option>
查看 styling using data attributes 的新文档以了解更多详细信息。
¥Check out the new documentation on styling using data attributes for some more details.
Tailwind Play 上的 Insiders 支持(Insiders support on Tailwind Play)
¥Insiders support on Tailwind Play
并非所有人都知道这一点,但我们已将 Tailwind CSS 的 insiders
版本发布到 npm,每次新的提交进入代码库时,它都会自动构建和部署。这样可以非常轻松地在新功能和修复被正式发布之前对其进行测试。
¥Not everyone knows this but we ship an insiders
build of Tailwind CSS to npm that is automatically built and deployed every single time a new commit lands in the repository. This makes it really easy to test out new features and fixes before they are actually tagged in a proper release.
现在,我们也提供了对 Tailwind Play 内部版本的访问权限,因此你无需设置项目即可体验前沿技术:
¥Well now we include access to the insiders build in Tailwind Play as well, so you can play with bleeding edge stuff without even setting up a project:

我们只在 Play 上保留最新的内部版本,因此如果你使用内部版本创建演示,请注意,如果下一个内部版本更改了你正在使用的某些未发布的功能,演示可能会崩溃。无论如何,你不应该把重要的东西放在那里,来吧,做个专业人士。
¥We only keep the latest insiders build on Play, so if you create a demo using an insiders build know that it might break if the next insiders build changes something in some unreleased feature you were using. You shouldn't be putting important things there anyways, come on be a professional.
Tailwind CSS + Phoenix v1.7
不久前,我们开始与 Phoenix 团队沟通,因为他们希望在未来的版本中默认使用 Tailwind CSS。我觉得这非常令人兴奋,并希望与他们合作,让这个开箱即用的体验更加美好。
¥A while ago we started talking with the Phoenix team because they wanted to ship Tailwind CSS by default in a future release. I thought this was super exciting, and wanted to work with them to make the out-of-the-box experience really beautiful.
我们设计了一个新的启动画面以及生成器系统所需的所有脚手架,这些将作为 Phoenix v1.7 的一部分发布。
¥We designed a new splash screen and all of the necessary scaffolding for their generator system, which will ship as part of Phoenix v1.7.

Phoenix 的创建者 Chris McCord 上周在 a great talk 上详细介绍了他们正在交付的所有 Tailwind CSS 内容,如果你想了解更多信息,值得一看。
¥Chris McCord the creator of Phoenix gave a great talk last week that walks through all of the Tailwind CSS stuff they are shipping, worth a watch if you're curious to learn more.
好了,这就是我们过去几周一直在努力完成的所有酷炫内容!
¥So there you go, that's all of the coolest stuff we've been working on over the last few weeks!
在接下来的一个月左右,我很期待构建一系列我们一直在设计的全新 Tailwind UI 组件,探索一些 Tailwind CSS 的 new feature ideas,并开始进行一些研发工作,看看用 Tailwind + Next.js 创建某种应用入门套件模板会是什么样子 - 如果我们能成功的话,我觉得那会很酷。
¥Over the next month or so I'm excited to build a bunch of new Tailwind UI components we've been designing, explore some new feature ideas for Tailwind CSS, and start doing some R&D on what it would look like to create a sort of application starter kit template with Tailwind + Next.js — think it could be pretty cool if we can nail it.
下次更新再见!
¥Catch you in the next update!