Introducing KickStart —  AI generated FormKit forms in seconds. Generate from a screenshot, edit with drag-and-drop or conversational AI, copy & paste as components or schema!
Try for free

创建一个 Tailwind CSS 主题

在本指南中,我们将逐步介绍为您的表单和输入框创建自定义 Tailwind 主题的过程。Tailwind 已经成为 CSS 实用类库的前沿,而 FormKit 在编写时就考虑到了它的功能。让我们开始吧!

SFC 构建工具

本指南假设您正在使用标准的 Vue 3 构建工具,如 Vite、Nuxt 3 或 Vue CLI,这些工具允许您导入 .vue 单文件组件。

内联使用

在大多数情况下不推荐

内联使用对于一次性覆盖或非常简单的表单来说可能很棒。要创建完整的主题,请继续阅读。

在代表组件的 .vue 文件的上下文中,可以使用 FormKit 提供的 section-key 类属性classes 属性 来创建 Tailwind 主题。

如果您的组件代表了整个表单,并且您的项目只需要一个表单,这可能就是您所需要的。这里有一个示例,展示了如何使用 section-key 属性和 classes 属性将相同的 Tailwind 类应用于 FormKit text 输入框:

加载实时示例

这是一种将 Tailwind 样式应用于您的 FormKit 表单的低门槛方式,但如果您有多个表单 — 或者您需要处理多种类型的输入框呢?在组件之间复制粘贴类列表并不理想,而且会随着时间的推移导致您的项目中的样式出现无意的变化。

让我们探索如何创建一个 Tailwind 主题 — 带有可配置选项 — 可以在全局级别覆盖项目中的所有输入框。

创建一个可配置的 FormKit 主题

按照以下说明,我们将创建一个类似于 https://themes.formkit.com 上可用的主题。如果您选择提供,这包括对用户可配置变量的支持。

多功能、可配置、MIT 许可的 Tailwind 主题,用于您的项目。花更少的时间进行样式设计 — 更多时间进行构建。
FormKit 主题

多功能、可配置、MIT 许可的 Tailwind 主题,用于您的项目。花更少的时间进行样式设计 — 更多时间进行构建。

一旦您的主题完成,您可以通过针对站点仓库开启一个 PR 将您的主题提交到 https://themes.formkit.com。一旦获得批准,它将通过 CLI 或 Web UI 可供其他人在他们的项目中使用。

初始化副本的起始主题

FormKit 提供了一个起始主题 —— 它带有结构样式和丰富的注释 —— 旨在帮助新作者创建自己的主题。

要开始,请在终端中运行以下命令:

npx formkit create-theme

这将为您下载一个干净的起始主题副本供您使用。起始主题是一个功能齐全的 Vite 应用程序,其中包括一个“厨房水槽”(Kitchen Sink),以帮助您看到您的类如何影响每个可用的 FormKit 输入。

接下来,您需要在 https://pro.formkit.com 登录并为 FormKit Pro 创建一个新的(免费的)开发密钥。这个密钥将允许您渲染包含在厨房水槽中的 FormKit Pro 元素。

将您的 FormKit Pro 密钥添加到项目根目录中的 .env 文件

FORMKIT_PRO_KEY=fk-**********

添加了您的专业密钥后,运行以下命令开始您的主题工作:

# 或使用 npm 或 yarn
pnpm install
pnpm dev

起始主题的结构

起始主题中的 src 目录包含以下重要文件和目录:

  • theme.ts:这是您主题的入口点。您将在此配置主题的元数据、变量,并导入您主题的 CSS 类列表以适用于每个输入。
    • meta:元信息,如主题名称、支持的输入,以及对浅色模式和深色模式支持的声明。
    • variables:将在您主题的 CSS 类列表中使用的变量 —— 被分配了 'editor' 的变量将在主题编辑器中为主题用户暴露 UI 控件。下面会有更多介绍。
    • inputs:输入名称的对象,每个都映射到一个包含节名称和类列表的对象。默认情况下,每个输入的类列表都作为单独的导入完成。
  • globals.ts:此文件包含输入的全局类。任何匹配的节名称(例如,'outer')将应用于 每个 FormKit 输入。这是一个节省时间的方法,但请谨慎使用。
  • familes/*.ts:比全局类更具体一步,这些文件包含每个输入家族的类列表。家族是类似输入的分组,共享样式是有意义的 —— 例如,'text' 家族包括 FormKit 支持的 16+ 输入。每个家族文件在顶部包含一个注释,列出了该家族中包含的输入。
  • inputs/*.ts:每个输入的最具体的类列表。这些类仅适用于文件名所指示的输入(假设您已在 theme.ts 中正确分配,这默认为您完成)。在适用的情况下,这些文件包括一个注释,指示它们从哪个家族继承类。

起始主题中的其余文件可以忽略(但不删除),因为它们是包含的 Vite 应用程序和厨房水槽的脚手架。它们不会对您发布的主题产生实质性影响。

使用变量

变量是一种强大的工具,可以在您的主题中重复使用值,并允许主题用户根据自己的喜好自定义您的主题。变量通过以下语法在输入的类列表中使用:

// global.ts
export default {
  outer: `$myVariable`
}

入门主题预定义了许多变量。

基本变量

以下变量为方便起见在入门主题中定义,但并_不_为主题用户提供任何UI:

  • accentColor
  • accentColorStrength
  • accentColorStrengthDark
  • colorTemperature
  • colorTemperatureStrength
  • colorTemperatureStrengthDark
  • inputMaxWidth

入门主题还附带以下变量,为主题用户提供UI控件:

  • radius,
  • spacing,
  • scale

您可以通过在变量对象中提供新的键/值对来创建自己的基本非用户可配置变量:

export default createTheme({
  ...
  variables: {
    ...
    textSize: 'lg'
  }
})

变量可以使用以下语法在输入的类列表中使用:

// globals.ts
export default {
  // 变成 'text-lg'
  label: 'text-$textSize'
}

将共享的常见值放入变量中,允许主题作者从单一位置快速调整其主题中所有类列表的值。

带有刻度的变量

Tailwind最好的方面之一是所有值都在可预测的刻度上操作。这意味着我们可以为变量提供一个“范围”,然后根据需要在我们的主题内上下移动刻度。

例如,spacing变量可能使用以下Tailwind刻度操作(0px0.511.522.53等)。通过提供一个scale和默认的value,我们可以随意地在刻度上上下移动。

spacing: {
  value: "2",
  // 我们可以定义一个我们可以逐步通过的刻度。
  // 默认值将用作起点。
  // 因为我们正在定义刻度,我们可以省略默认的
  // Tailwind值,如'0'和'px',如果它们对我们的用例没有意义。
  scale: ["0.5", "1", "1.5", "2", "2.5", "3", "4", "6"]
},

有了上面定义的变量,我们现在可以在我们的类列表中使用以下语法动态地在刻度上上下移动:

// globals.ts
export default {
  // 变成 'mb-3' — 在我们刻度上向上两步
  outer: 'mb-$spacing(2)',
  // 变成 'mb-2' — 我们的默认刻度值
  label: 'mb-$spacing',
  // 变成 'mb-1 — 在我们刻度上向下两步'
  help: 'mb-$spacing(-2)'
  // 使用相同变量的多个值的混合
  // 变成 'mb-1 px-3 py-2'
  inner: 'mb-$spacing(-2) px-$spacing(2) py-$spacing'
}

变量永远不会超过其刻度的限制,所以mb-$spacing(100)将变成mb-6,因为那是我们提供的刻度的上限。

具有用户可控制值的变量

变量很酷 — 但真正的力量来自于将变量暴露给我们主题的最终用户,并允许他们根据自己的喜好配置值。

为此,我们为变量提供了一个 editor 值。editor 决定了在主题定制面板中暴露哪种 UI 控件。可用的 editor 值如下:

  • buttons:一组按钮,用于选择一个值。主题作者必须提供他们自己的刻度。
  • color:一组每个代表默认 Tailwind 颜色的色板。默认包括所有 22 种可用 Tailwind 颜色的刻度。
  • fontSize:一组带有不同大小的字母 A 的按钮。默认包括从 xs9xl 的刻度。
  • radius:一组每个代表不同边框圆角强度的按钮。默认包括从 rounded-nonerounded-full 的刻度。
  • shadow:一个带有所选阴影级别表示的步进器。默认包括从 shadow-noneshadow-2xl 的刻度。
  • spacing:一个滑块,其值范围从开始的紧凑间距到结束的宽松间距。默认包括从 096 的刻度。
  • select:一个标准的 HTML 选择列表,可以包含任意数量的值。主题作者必须提供他们自己的刻度。

您可以通过查看 Regenesis 主题的编辑器 UI 这里来看到每个 editor 值的示例。

我们可以更新我们的 spacing 变量以使用适当的编辑器:

spacing: {
  editor: "spacing",
  value: "2"
}

现在我们将在主题编辑器中看到我们的 spacing 变量的一个新控件,带有一个滑块,允许我们在默认 Tailwind 刻度中从 096

用户选择影响动态值

当您暴露一个变量时,用户在修改变量时正在改变基础值。这意味着像 mb-$spacing(1) 这样的变量使用总是在用户_选择的_值之上的刻度上的一步,而不是主题的默认值。

为用户可控制的变量设置 minmax

在大多数情况下,限制用户可配置变量的可用刻度是有意义的。允许我们的用户调整 spacing 是很好的,但我们可能不希望他们能够将值调整到 96 或全部降低到 0。我们可以通过在变量上使用 minmax 属性来限制用户可用的刻度范围。

spacing: {
  editor: "spacing",
  value: "2",
  min: "1",
  max: "3"
}

这意味着我们的 spacing 变量现在只允许通过定制器 UI 选择 11.522.53 这些值。

创建一次性的最小值和最大值约束

有时作为主题作者,您需要将可用值的范围限制或扩展到超出变量默认的 minmax 定义。您可以通过向变量的内联实例传递额外的 minmax 参数来实现这一点。

提供的 minmax必须 是值或与之关联的变量的比例尺 —— 无论是编辑器的默认比例尺还是主题作者定义的自定义比例尺。

您还可以提供一个通配符 * 作为第二个参数,以允许关联比例尺上的任何有效值。

// globals.ts
export default {
  // 在比例尺上向上步进5步。
  // 将最小值设置为3
  // 并将最大值设置为8
  outer: 'mb-$spacing(5, 3, 8)',
  // 在比例尺上向下步进2步
  // 将最小值设置为1
  // 并将最大值设置为2
  label: 'mb-$spacing(-2, 1, 2)',
  // 在比例尺上向下步进2步
  // 允许比例尺上的任何有效值
  help: 'mb-$spacing(-2,*)'
}

覆盖默认编辑器比例尺

一些 editor 类型,如 scalecolor,带有默认的比例尺。然而,我们可以通过提供自定义的 scale 属性来覆盖默认值。

accentColor: {
  editor: "color",
  value: "blue",
  // 从默认比例尺中排除所有的 "gray" 颜色
  scale: [
    "red",
    "orange",
    "amber",
    "yellow",
    "lime",
    "green",
    "emerald",
    "teal",
    "cyan",
    "sky",
    "blue",
    "indigo",
    "violet",
    "purple",
    "fuchsia",
    "pink",
    "rose",
  ],
},

您甚至可以将自定义比例尺与 minmax 属性结合起来,创建完全超出 Tailwind 默认比例尺中可用值的新比例尺。

scale: {
  editor: "fontSize",
  value: "base",
  scale: [
    // 一个自定义大小和相应的
    // 该大小的自定义行高。
    "[11px] [line-height:1em]",

    // Tailwind 的默认值
    // 在我们认为合理的范围内。
    "xs",
    "sm",
    "base",
    "lg",
    "xl",
    "2xl",
  ],
  min: "sm",
  max: "lg",
},

@formkit/theme-starter 主题本身中还有更多注释,以帮助您在工作时找到方向。

发布您的主题

当您完成主题创建后,可以使用随附的发布脚本来构建并将您的主题发布到 npm。

首先,请确保您已经修改了主题的 meta 键和 package.json 文件的内容,以准确反映您的主题名称、描述、版本和作者信息。

FormKit 主题前缀

建议您使用前缀 formkit-theme- 来命名您的主题,以帮助用户发现并理解您的包是一个 FormKit 主题。

当您准备好时,在终端中运行以下命令


# 强烈推荐使用pnpm
pnpm release

该命令会构建你的主题,运行一个linter以确保你的package.json文件有效,运行一个脚本来提升你的主题版本(如果你使用语义化提交信息,还会自动创建发布说明),然后将你的主题以你提供的包名发布到npm

安装已发布的第三方主题

要使用你或其他人发布到npm的第三方主题,首先将其作为开发依赖安装到你的项目中:

pnpm add -D formkit-theme-my-theme
PNPM 需要 formkit CLI 依赖

如果你在使用pnpm,你需要确保你的项目中有formkit命令行包作为开发依赖。如果你没有使用pnpm,你可以跳过这一步。

pnpm add -D formkit

一旦主题作为依赖安装后,你可以使用formkit CLI的theme命令来构建你的主题。

# 将从你的本地 node_modules 解析
npx formkit@latest theme --theme=formkit-theme-my-theme

该命令将在你项目的根目录下生成一个formkit.theme.(mjs|ts)文件。为了完成设置,你需要做以下两件事:

  • 从你构建的主题中导入rootClasses函数到你的formkit.config文件中
  • formkit.theme文件添加到你的tailwind.config文件的content数组中。
// formkit.config.ts
import { defaultConfig } from '@formkit/vue'
import { rootClasses } from './formkit.theme'

export default defaultConfig({
  ...
  config: {
    rootClasses,
  },
})
// tailwind.config.js
module.exports = {
  ...
  content: [
    "./app.vue",
    "./formkit.theme.ts" // <-- 添加你的主题文件
  ]
}

自定义已发布主题的变量

需要更改主题中的一些可用变量吗?这可以通过在一个中间文件中导入并覆盖你的主题,然后将该中间文件传递给formkit CLI来完成。以这个例子,让我们在项目的根目录下创建一个名为formkit.theme.config.ts的文件。在这个文件中,我们将导入我们的主题并重新导出它,传入变量覆盖。

// formkit.theme.config.ts
import myTheme from 'formkit-theme-my-theme'

export default myTheme({
  // 修改你的主题中任何可用的变量
  radius: 'rounded-full',
  spacing: '2.5',
  accentColor: 'violet'
})

现在你可以使用formkit CLI来构建你的主题,并应用你的自定义设置。


# 将使用您的变量覆盖生成您的主题
npx formkit@latest theme --theme=formkit.theme.config.ts

按照上面部分的相同说明安装生成的 formkit.theme.(mjs|ts) 文件 —— 将 rootClasses 添加到您的 formkit.config 文件中,并将 formkit.theme.(mjs|ts) 文件包含在您的 tailwind.config 文件的内容数组中。

将您的主题提交到 themes.formkit.com

为您的主题感到自豪吗?提供了其他 FormKit 用户会喜欢使用的独特内容吗?

打开一个拉取请求themes.formkit.com 仓库,并提交您的主题!一旦获得批准,它将被列入主题画廊,并且任何人都可以像使用提供的第一方 FormKit 主题一样轻松地在他们的项目中使用。

# 一旦合并,可以直接通过名称从 themes.formkit.com 安装
npx formkit@latest theme --theme=my-theme

获取帮助

编写全面的 FormKit 主题是一项庞大的任务。如果您遇到困难,需要想法,或者想要讨论为 FormKit 创建主题,请一定要加入我们的官方 Discord 社区。我们很乐意提供帮助!