Tailwind UI 中的所有组件都针对最新版本的 Tailwind CSS 设计,当前版本为 Tailwind CSS v3.4。为了确保你使用的是最新版本的 Tailwind,请通过 npm 更新
npm install tailwindcss@latest
Tailwind UI 中的所有示例都依赖于默认的 Tailwind CSS 配置,但有些示例依赖于其他第一方插件,如 @tailwindcss/forms
、@tailwindcss/typography
和 @tailwindcss/aspect-ratio
。
如果示例需要任何插件或配置更改,将在示例顶部的注释中说明。
如果你不熟悉 Tailwind CSS,你可能需要 阅读 Tailwind CSS 文档,以便充分利用 Tailwind UI。
我们使用 Inter 作为所有 Tailwind UI 示例的字体,因为它是一款用于 UI 设计的精美字体,并且完全开源且免费。使用自定义字体很好,因为它可以使组件在所有浏览器和操作系统上看起来相同。
当然,你可以在自己的项目中使用任何你想要的字体,但如果你想使用 Inter,最简单的方法是先通过 CDN 添加它
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
然后在你的 Tailwind 配置中将 "Inter var" 添加到你的 "sans" 字体系列中
// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
theme: {
extend: {
fontFamily: {
sans: ['Inter var', ...defaultTheme.fontFamily.sans],
},
},
},
// ...
}
Tailwind UI 中的所有组件都以三种格式提供:React、Vue 和普通 HTML。
React 和 Vue 示例开箱即用,并且由 Headless UI 提供支持,这是一个我们设计用于与 Tailwind CSS 无缝集成的无样式组件库。
普通 HTML 示例 **不包含任何 JavaScript**,专为喜欢自己编写任何必要 JavaScript 或希望与 React 或 Vue 以外的框架集成的用户设计。
绝大多数组件根本不需要 JavaScript,开箱即用,但交互式组件,例如下拉菜单、对话框等,需要您编写一些 JS 代码才能使其按预期工作。
在这些情况下,我们在 HTML 中提供了一些简单的注释来解释一些事情,例如您需要使用哪些类来实现不同的状态(例如,切换开关处于打开或关闭状态),或者我们建议使用哪些类来将元素过渡到屏幕上或从屏幕上移除(例如,对话框打开)。
我们尽力确保 Tailwind UI 中的所有标记尽可能地易于访问,但当您构建交互式组件时,**许多无障碍最佳实践只能通过 JavaScript 实现。**
例如
aria-expanded="true"
,在切换开关打开时将aria-checked
设置为 true,在导航自动完成中的选项时更新aria-activedescendant
,等等)
如果您将 Tailwind UI 与 React 或 Vue 一起使用,所有这些复杂性都会由Headless UI自动为您处理,但如果您提供自己的 JS 代码,**您有责任在添加交互行为时遵循无障碍最佳实践。**
要了解有关构建无障碍 UI 组件的更多信息,我们建议您学习由 W3C 发布的WAI-ARIA Authoring Practices。
当某个元素需要根据某些状态应用不同的类(例如,切换开关处于打开或关闭状态)时,我们会在元素正上方的注释中列出每个状态的类
<!-- On: "bg-indigo-600", Off: "bg-gray-200" -->
<span aria-checked="false" class="bg-gray-200 relative inline-block flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:shadow-outline" role="checkbox" tabindex="0">
<!-- On: "translate-x-5", Off: "translate-x-0" -->
<span aria-hidden="true" class="translate-x-0 inline-block h-5 w-5 rounded-full bg-white shadow transform transition ease-in-out duration-200"></span>
</span>
我们提供的 HTML 始终预先配置为定义的某个状态,并且在切换状态时需要更改的类始终位于类列表的开头,因此很容易找到。
例如,要将此 HTML 适配到 Alpine.js,您可以使用 :class
指令根据在 x-data
中声明的某个状态有条件地应用正确的类。
<span
x-data="{ isOn: false }"
@click="isOn = !isOn"
:aria-checked="isOn"
:class="{'bg-indigo-600': isOn, 'bg-gray-200': !isOn }"
class="bg-gray-200 relative inline-block flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:shadow-outline"
role="checkbox"
tabindex="0"
>
<span
aria-hidden="true"
:class="{'translate-x-5': isOn, 'translate-x-0': !isOn }"
class="translate-x-0 inline-block h-5 w-5 rounded-full bg-white shadow transform transition ease-in-out duration-200"
></span>
</span>
我们在此包含了一个基本的点击处理程序来演示一般思路,但请参考 WAI-ARIA 作者实践 在构建此类组件时,以确保您实现所有必要的键盘交互并正确管理任何必需的 ARIA 属性。
对于应该动态显示或隐藏的元素(如下拉菜单上的面板),我们在动态元素正上方的注释中包含了推荐的过渡样式。
<div class="relative ...">
<button type="button" class="...">
Options
</button>
<!--
Show/hide this element based on the dropdown state
Entering: "transition ease-out duration-100 transform"
From: "opacity-0 scale-95"
To: "opacity-100 scale-100"
Closing: "transition ease-in duration-75 transform"
From: "opacity-100 scale-100"
To: "opacity-0 scale-95"
-->
<div class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg">
<div class="rounded-md bg-white shadow-xs">
<!-- Snipped -->
</div>
</div>
</div>
例如,要将此 HTML 适配到 Alpine.js,您将使用 x-transition
指令在过渡生命周期的每个点应用正确的类。
<div x-data="{ isOpen: false }" class="relative ...">
<button type="button" @click="isOpen = !isOpen" class="...">
Options
</button>
<div
x-show="isOpen"
x-transition:enter="transition ease-out duration-100 transform"
x-transition:enter-start="opacity-0 scale-95"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75 transform"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-95"
class="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg"
>
<div class="rounded-md bg-white shadow-xs">
<!-- Snipped -->
</div>
</div>
</div>
我们在此包含了一个基本的点击处理程序来演示一般思路,但请参考 WAI-ARIA 作者实践 在构建此类组件时,以确保您实现所有必要的键盘交互并正确管理任何必需的 ARIA 属性。
由于 Tailwind UI 中包含的原生 HTML 示例无法利用循环等功能,因此存在大量在实际项目中不会出现的重复,在实际项目中,HTML 是从某个动态数据源生成的。例如,我们可能会给您一个包含 5 个列表项的列表组件,每个列表项都重复了所有实用程序,而在您的项目中,您实际上将通过循环遍历数组来生成这些列表项。
在将我们的示例适配到您自己的项目时,我们建议根据需要创建可重用的模板片段或 JS 组件来管理任何重复。
在 Tailwind CSS 网站的 “提取组件”文档 中了解有关此内容的更多信息。
Tailwind UI for React 依赖于 Headless UI 来为所有交互行为提供支持,并依赖于 Heroicons 来提供图标,因此您需要将这两个库添加到您的项目中。
npm install @headlessui/react @heroicons/react
这些库和 Tailwind UI 本身都需要 React >= 16。.
所有 React 示例都作为简单的单个组件提供,并且不假设您希望如何分解事物、希望公开哪些道具 API 以及从哪里获取任何数据。
一些数据已被提取到基本的局部变量中,只是为了清理重复并使代码更易于阅读和理解,但我们尽量减少了操作,以避免强加任何不必要的严格意见。
在将 Tailwind UI 中的代码适配到您自己的项目时,您应该根据需要将示例分解成更小的组件,以实现项目所需的任何重用级别。
例如,您可以从这个堆叠列表组件开始
const people = [
{
name: 'Calvin Hawkins',
email: '[email protected]',
image:
'https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
{
name: 'Kristen Ramos',
email: '[email protected]',
image:
'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
{
name: 'Ted Fox',
email: '[email protected]',
image:
'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
]
export default function Example() {
return (
<ul className="divide-y divide-gray-200">
{people.map((person) => (
<li key={person.email} className="py-4 flex">
<img className="h-10 w-10 rounded-full" src={person.image} alt="" />
<div className="ml-3">
<p className="text-sm font-medium text-gray-900">{person.name}</p>
<p className="text-sm text-gray-500">{person.email}</p>
</div>
</li>
))}
</ul>
)
}
在为自己的项目调整内容、将其分解成单独的组件并连接数据源后,它可能看起来更像这样
function HockeyTeamItem({ team }) {
return (
<li className="py-4 flex">
<img className="h-10 w-10 rounded-full" src={team.logo} alt="" />
<div className="ml-3">
<p className="text-sm font-medium text-gray-900">{team.name}</p>
<p className="text-sm text-gray-500">{team.city}</p>
</div>
</li>
)
}
export default function HockeyTeamList({ teams }) {
return (
<ul className="divide-y divide-gray-200">
{teams.map((team) => <HockeyTeamItem key={team.id} team={team} />)}
</ul>
)
}
Tailwind UI 更像是一套蓝图、模式和想法,而不是一个僵化的 UI 工具包。最终得到的代码是你的,你可以根据自己的喜好进行调整。
Tailwind UI for Vue 依赖于 Headless UI 来提供所有交互行为,并依赖于 Heroicons 来提供图标,因此您需要将这两个库添加到您的项目中
npm install @headlessui/vue @heroicons/vue
这些库和 Tailwind UI 本身都需要 Vue 3+。我们目前不提供对 Vue 2 的支持。
所有 Vue 示例都以一个简单的单组件形式提供,不假设您希望如何分解组件、要公开哪些 prop API 以及从哪里获取数据。
一些数据已被提取到基本的局部变量中,只是为了清理重复并使代码更易于阅读和理解,但我们尽量减少了操作,以避免强加任何不必要的严格意见。
在将 Tailwind UI 中的代码适配到您自己的项目时,您应该根据需要将示例分解成更小的组件,以实现项目所需的任何重用级别。
例如,您可以从这个堆叠列表组件开始
<template>
<ul class="divide-y divide-gray-200">
<li v-for="person in people" :key="person.email" class="py-4 flex">
<img class="h-10 w-10 rounded-full" :src="person.image" alt="" />
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">{{ person.name }}</p>
<p class="text-sm text-gray-500">{{ person.email }}</p>
</div>
</li>
</ul>
</template>
<script>
const people = [
{
name: 'Calvin Hawkins',
email: '[email protected]',
image:
'https://images.unsplash.com/photo-1491528323818-fdd1faba62cc?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
{
name: 'Kristen Ramos',
email: '[email protected]',
image:
'https://images.unsplash.com/photo-1550525811-e5869dd03032?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
{
name: 'Ted Fox',
email: '[email protected]',
image:
'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80',
},
]
export default {
setup() {
return {
people,
}
},
}
</script>
在为自己的项目调整内容、将其分解成单独的组件并连接数据源后,它可能看起来更像这样
<!-- HockeyTeamList.vue -->
<template>
<ul class="divide-y divide-gray-200">
<HockeyTeamItem v-for="team in teams" :key="team.id" :team="team"/>
</ul>
</template>
<script>
export default {
props: {
teams: Array
},
}
</script>
<!-- HockeyTeamListItem.vue -->
<template>
<li class="py-4 flex">
<img class="h-10 w-10 rounded-full" :src="team.logo" alt="" />
<div class="ml-3">
<p class="text-sm font-medium text-gray-900">{{ team.name }}</p>
<p class="text-sm text-gray-500">{{ team.city }}</p>
</div>
</li>
</template>
<script>
export default {
props: {
team: Object
},
}
</script>
Tailwind UI 更像是一套蓝图、模式和想法,而不是一个僵化的 UI 工具包。最终得到的代码是你的,你可以根据自己的喜好进行调整。
我们在 Tailwind UI 中使用的所有图标都来自 Heroicons,这是一个免费的 MIT 许可的图标集,我们在开始开发 Tailwind UI 时自己设计和开发的。
Tailwind UI 中的图像几乎全部来自 Unsplash。如果您需要免费使用的摄影作品,这是一个很好的资源。
Tailwind UI 中的一些示例使用了来自 Lucid Illustrations 包的插图,该包由 Pixsellz 提供。您可以在 他们的网站 上获取完整的插图集并查看他们的其他设计资源。
我们已经停止提供 Figma 资产,以便我们可以将精力集中在使用 Tailwind CSS 构建更多优秀的示例上。
我们曾经为 Tailwind UI 提供 Figma 资产,但它们维护起来实在太费力,而且很少有人使用。我们做出了一个艰难的决定,停止提供它们,以便我们可以将更多时间花在实际代码上,我们认为这是我们能够提供最大价值的地方。
Tailwind UI 的客户可以下载我们发布的最终 Figma 文件,但请注意 **Figma 文件不会更新**,并且不包含 2021 年 7 月 14 日之后发布的任何示例。