@shadcn/ui 的 <AutoForm />
AutoForm 是一个 React 组件,可以根据 zod schema 自动创建 @shadcn/ui 表单。
在线演示可以在 https://vantezzen.github.io/auto-form/ 查看。
何时使用 AutoForm?
AutoForm 主要用于为现有 zod schema 的内部和低优先级表单提供即插即用的表单构建器。例如,如果你已经为你的 API 创建了 zod schema,并想创建一个简单的管理面板来编辑用户资料,只需将 schema 传递给 AutoForm 即可。
AutoForm 尽可能原生地使用 @shadcn/ui 组件,只进行最少的类覆盖。这样,如果你在项目中自定义了 @shadcn/ui 组件,AutoForm 不会干扰你的自定义设置。
由于表单几乎总是变得越来越复杂,AutoForm 提供了自定义表单渲染方式的选项(例如使用 fieldConfig
选项和依赖支持),并提供了进一步自定义表单的方法(例如渲染自定义父组件和添加自定义字段类型)。
然而,AutoForm 并不旨在成为一个功能齐全的表单构建器。它不打算支持 zod schema 中的每个边缘情况或允许构建复杂的多页表单。如果你需要更多自定义,可以在你的项目中自定义 AutoForm 的渲染器,或使用更强大的表单构建器,如 Formik - 尽管这些需要更专门的配置,而不是简单地支持你的 zod schema。关于如何扩展 AutoForm 以实现更强大的基于 YAML 的多页表单,请参见 AutoForm YAML。
安装
该组件依赖于 shadcn/ui 的以下组件:
- accordion
- button
- calendar
- card
- checkbox
- form
- input
- label
- popover
- radio-group
- select
- separator
- switch
- textarea
- tooltip
- toggle
你可以一次性安装所有组件:
npx shadcn-ui@latest add accordion button calendar card checkbox form input label popover radio-group select separator switch textarea tooltip toggle
要安装组件本身,将 src/components/ui
中的 auto-form
文件夹和 date-picker.tsx
复制到你项目的 ui 文件夹中。
你可以删除 auto-form/tests
中的测试文件夹。
字段类型
目前,以下字段类型开箱即用:
- boolean(复选框、开关)
- date(日期选择器)
- enum(选择、单选组)
- number(输入框)
- string(输入框、文本域)
你可以通过在 auto-form/config.tsx
中的 INPUT_COMPONENTS
对象添加其他字段类型来支持它们。
使用方法
基本用法:
"use client"; import AutoForm, { AutoFormSubmit } from "./components/ui/auto-form"; import * as z from "zod"; // 使用 zod 定义你的表单 schema const formSchema = z.object({ username: z .string({ required_error: "用户名是必填项。", }) // 你可以像平常一样使用 zod 的内置验证 .min(2, { message: "用户名至少需要 2 个字符。", }), password: z .string({ required_error: "密码是必填项。", }) // 使用 "describe" 方法设置标签 // 如果没有设置标签,将使用字段名并取消驼峰命名 .describe("你的安全密码") .min(8, { message: "密码至少需要 8 个字符。", }), favouriteNumber: z.coerce // 使用数字和日期时,必须使用 coerce .number({ invalid_type_error: "喜爱的数字必须是一个数字。", }) .min(1, { message: "喜爱的数字必须至少为 1。", }) .max(10, { message: "喜爱的数字最多为 10。", }) .default(5) // 你可以设置默认值 .optional(), acceptTerms: z .boolean() .describe("接受条款和条件。") .refine((value) => value, { message: "你必须接受条款和条件。", path: ["acceptTerms"], }), // Date 将显示一个日期选择器 birthday: z.coerce.date().optional(), sendMeMails: z.boolean().optional(), // Enum 将显示一个选择框 color: z.enum(["red", "green", "blue"]), // 创建子对象以创建手风琴部分 address: z.object({ street: z.string(), city: z.string(), zip: z.string(), }), }); function App() { return ( <AutoForm // 将 schema 传递给表单 formSchema={formSchema} // 你可以为每个字段添加额外的配置 // 以自定义 UI fieldConfig={{ password: { // 使用 "inputProps" 将 props 传递给输入组件 // 你可以使用组件接受的任何 props inputProps: { type: "password", placeholder: "••••••••", }, }, favouriteNumber: { // 设置 "description",将显示在字段下方 description: "你最喜欢的 1 到 10 之间的数字。", }, acceptTerms: { inputProps: { required: true, }, // 你可以在描述中使用 JSX description: ( <> 我同意{" "} <a href="#" className="text-primary underline" onClick={(e) => { e.preventDefault(); alert("点击了条款和条件。"); }} > 条款和条件 </a> 。 </> ), }, birthday: { description: "我们需要你的生日来给你送礼物。", }, sendMeMails: { // 布尔值默认使用复选框,你可以改用开关 fieldType: "switch", }, }} // 可选地,定义字段之间的依赖关系 dependencies={[ { // 当 "sendMeMails" 未被选中时隐藏 "color",因为我们只需要在发送邮件时知道颜色 sourceField: "sendMeMails", type: DependencyType.HIDES, targetField: "color", when: (sendMeMails) => !sendMeMails, }, ]} > {/* 传入 AutoFormSubmit 或 type="submit" 的按钮。 或者,你可以不传递提交按钮 以创建自动保存表单等。 */} <AutoFormSubmit>立即发送</AutoFormSubmit> {/* 传递给表单的所有子元素将在表单下方渲染。 */} <p className="text-gray-500 text-sm"> 提交此表单即表示你同意我们的{" "} <a href="#" className="text-primary underline"> 条款和条件 </a> 。 </p> </AutoForm> ); }
Next.js 和 RSC
由于 zod schema 和值需要序列化到你的事件监听器,AutoForm 只能在客户端 React 组件中使用。如果你想在 Next.js 应用中使用它,只需在你的组件中标记 "use client":
// MyPage.tsx export default function MyPage() { return ( <div> <MyForm /> </div> ); }
// MyForm.tsx "use client"; import AutoForm from "./components/ui/auto-form"; export default function MyForm() { return <AutoForm onSubmit={...} ... />; }
### Zod 配置
#### 验证
你的表单 schema 可以使用 zod 的任何验证方法,包括 refine。
AutoForm 能够自动将一些 zod 的验证元素转换为 HTML 属性。例如,如果你使用 `zod.string().min(8)`,输入框将自动具有 `minlength="8"` 属性。
HTML 不支持的验证方法将在表单提交时自动检查。
#### 描述
你可以使用 `describe` 方法为每个字段设置标签和描述。如果没有设置标签,将使用字段名并去掉驼峰命名。
```tsx
const formSchema = z.object({
username: z.string().describe("你的用户名"),
someValue: z.string(), // 将显示为 "Some Value"
});
强制转换
使用数字和日期时,你应该使用 coerce。这是因为输入元素可能返回应自动转换的字符串。
const formSchema = z.object({ favouriteNumber: z.coerce.number(), birthday: z.coerce.date(), });
可选字段
默认情况下,所有字段都是必填的。你可以使用 optional
方法使字段成为可选的。
const formSchema = z.object({ username: z.string().optional(), });
默认值
你可以使用 default
方法为字段设置默认值。
const formSchema = z.object({ favouriteNumber: z.number().default(5), });
如果你想为日期设置默认值,请先使用 new Date(val)
将其转换为 Date。
子对象
你可以嵌套对象来创建手风琴式部分。
const formSchema = z.object({ address: z.object({ street: z.string(), city: z.string(), zip: z.string(), // 你可以根据需要嵌套对象 nested: z.object({ foo: z.string(), bar: z.string(), nested: z.object({ foo: z.string(), bar: z.string(), }), }), }), });
与普通对象一样,你可以使用 describe
方法为该部分设置标签和描述:
const formSchema = z.object({ address: z .object({ street: z.string(), city: z.string(), zip: z.string(), }) .describe("你的地址"), });
选择/枚举
AutoForm 支持 enum
和 nativeEnum
来创建选择字段。
const formSchema = z.object({ color: z.enum(["red", "green", "blue"]), }); enum BreadTypes { // 对于原生枚举,你也可以定义一个带后缀的枚举来设置自定义标签 White = "白面包", Brown = "全麦面包", Wholegrain = "全谷物面包", Other, } // 请注意,zod 将验证并返回枚举标签,而不是枚举值! const formSchema = z.object({ bread: z.nativeEnum(BreadTypes), });
数组
AutoForm 支持对象数组。由于从字符串/数字等数组中推断字段标签等信息比较困难,因此只支持对象数组。
const formSchema = z.object({ guestListName: z.string(), invitedGuests: z .array( // 定义每个项目的字段 z.object({ name: z.string(), age: z.coerce.number(), }), ) // 可选设置自定义标签 - 否则将从字段名推断 .describe("受邀参加派对的客人"), });
数组不支持作为表单 schema 的根元素。
你也可以使用 .default() 设置数组的默认值,但请确保数组元素与 schema 结构相同。
const formSchema = z.object({ guestListName: z.string(), invitedGuests: z .array( // 定义每个项目的字段 z.object({ name: z.string(), age: z.coerce.number(), }), ) .describe("受邀参加派对的客人") .default([ { name: "John", age: 24, }, { name: "Jane", age: 20, }, ]), });
字段配置
由于 zod 不允许向 schema 添加其他属性,你可以使用 fieldConfig
属性为每个字段的 UI 添加额外配置。
<AutoForm fieldConfig={{ // 在此处为每个字段添加配置 - 不要添加字段名以保留所有默认值 username: { // 配置在这里 }, }} />
输入属性
你可以使用 inputProps
属性将属性传递给输入组件。你可以使用 HTML 组件接受的任何属性。
<AutoForm fieldConfig={{ username: { inputProps: { type: "text", placeholder: "用户名", }, }, }} /> // 这将被渲染为: <input type="text" placeholder="用户名" /* ... */ />
通过在 inputProps
中使用 showLabel
属性可以禁用输入的标签。
<AutoForm fieldConfig={{ username: { inputProps: { type: "text", placeholder: "用户名", showLabel: false, }, }, }} />
字段类型
默认情况下,AutoForm 将使用 Zod 类型来确定使用哪个输入组件。你可以使用 fieldType
属性来覆盖此行为。
<AutoForm fieldConfig={{ sendMeMails: { // 布尔值默认使用复选框,这里改用开关 fieldType: "switch", }, }} />
支持的字段类型完整列表已经被定义。当前支持的类型有:
- "checkbox"(布尔值默认)
- "switch"
- "date"(日期默认)
- "select"(枚举默认)
- "radio"
- "textarea"
- "fallback"(其他所有类型默认,简单输入字段)
或者,你可以将 React 组件传递给 fieldType
属性以使用自定义组件。
<AutoForm fieldConfig={{ sendMeMails: { fieldType: ({ label, isRequired, field, fieldConfigItem, fieldProps, }: AutoFormInputComponentProps) => ( <FormItem className="flex flex-row items-start space-x-3 space-y-0 rounded-md border p-4"> <FormControl> <Switch checked={field.value} onCheckedChange={field.onChange} {...fieldProps} /> </FormControl> <div className="space-y-1 leading-none"> <FormLabel> {label} {isRequired && <span className="text-destructive"> *</span>} </FormLabel> {fieldConfigItem.description && ( <FormDescription>{fieldConfigItem.description}</FormDescription> )} </div> </FormItem> ), }, }} />
描述
你可以使用 description
属性在字段下方添加描述。
<AutoForm fieldConfig={{ username: { description: "输入一个唯一的用户名。这将显示给其他用户。", }, }} />
你可以在描述中使用 JSX。
自定义父组件
你可以使用 renderParent
属性自定义输入的父元素,以添加装饰等。
默认情况下,这是一个 React 片段。
<AutoForm fieldConfig={{ username: { renderParent: ({ children }) => ( <div className="flex items-end gap-3"> <div className="flex-1"> {children} // 这是带有标签等的输入框 </div> <div> <Button type="button">检查</Button> </div> </div> ), }, }} />
访问表单数据
有两种方式可以访问表单数据:
onSubmit
推荐的方式是使用 onSubmit
属性。当表单提交且数据有效时,该函数会被调用。
<AutoForm onSubmit={(data) => { // 处理数据 // 数据会自动通过 zod 进行验证和转换 }} />
受控表单
你也可以使用 values
和 onValuesChange
属性来自行控制表单数据。
const [values, setValues] = useState<Partial<z.infer<typeof formSchema>>>({}); <AutoForm values={values} onValuesChange={setValues} />;
请注意,使用这种方法时,数据不会被验证或转换,因为它们会立即更新。
或者,你可以使用 onParsedValuesChange
来获取只有在值可以被 zod 验证和解析时才更新的值:
const [values, setValues] = useState<z.infer<typeof formSchema>>({}); <AutoForm values={values} onParsedValuesChange={setValues} />;
提交表单
你可以使用 AutoFormSubmit
组件来创建一个提交按钮。
<AutoForm> <AutoFormSubmit>立即发送</AutoFormSubmit> </AutoForm> // 或者 <AutoForm> <button type="submit">立即发送</button> </AutoForm>
添加其他元素
所有传递给 AutoForm
组件的子元素都会在表单下方渲染。
<AutoForm> <AutoFormSubmit>立即发送</AutoFormSubmit> <p className="text-gray-500 text-sm"> 提交此表单即表示您同意我们的{" "} <a href="#" className="text-primary underline"> 条款和条件 </a> 。 </p> </AutoForm>
依赖关系
AutoForm 允许您在字段之间添加依赖关系,以根据其他字段的值控制字段。为此,可以向 AutoForm
组件传递一个 dependencies
数组。
<AutoForm dependencies={[ { // 当年龄为18岁或以上时,"age"隐藏"parentsAllowed" sourceField: "age", type: DependencyType.HIDES, targetField: "parentsAllowed", when: (age) => age >= 18, }, { // 如果未选中"素食主义者"复选框,则从"mealOptions"中隐藏"惠灵顿牛排"选项 sourceField: "vegetarian", type: DependencyType.SETS_OPTIONS, targetField: "mealOptions", when: (vegetarian, mealOption) => vegetarian && mealOption !== "惠灵顿牛排", options: ["意大利面", "沙拉"], }, ]} />
支持以下依赖类型:
DependencyType.HIDES
:当when
函数返回 true 时隐藏目标字段DependencyType.DISABLES
:当when
函数返回 true 时禁用目标字段DependencyType.REQUIRES
:当when
函数返回 true 时将目标字段设置为必填DependencyType.SETS_OPTIONS
:当when
函数返回 true 时将目标字段的选项设置为options
数组
when
函数接收源字段的值和目标字段的值作为参数,应返回一个布尔值,以指示是否应用依赖关系。
请注意,依赖关系在返回 false
时不会导致相反的操作 - 例如,如果您在 zod schema 中将字段标记为必填(即不显式设置 optional
),在 REQUIRES
依赖中返回 false
不会将其标记为可选。相反,您应该使用 zod 的 optional
方法将其默认标记为可选,并使用 REQUIRES
依赖在满足依赖条件时将其标记为必填。
请注意,依赖关系对表单的验证没有任何影响。您应该使用 zod 的 refine
方法根据其他字段的值验证表单。
您可以为同一字段和依赖类型创建多个依赖关系 - 例如,根据多个其他字段隐藏一个字段。这将在满足任何依赖关系时隐藏该字段。
贡献
欢迎贡献!请提出问题或提交拉取请求。
- Fork 仓库
- 克隆您的 fork 并使用
npm install
安装依赖项 - 运行
npm run dev
启动开发服务器并进行更改 - 运行
npm run fix
运行格式化程序和 linter - 运行
npm test
运行测试 - 提交您的更改并打开拉取请求
添加新组件
如果您想添加新组件,请确保将其添加到 auto-form/config.tsx
中的 INPUT_COMPONENTS
对象中。
- 在
src/components/ui/auto-form/fields
中创建一个新组件。您可以复制现有组件(如input.tsx
)作为起点。 - 将组件添加到
auto-form/config.tsx
中的INPUT_COMPONENTS
对象中,以给它一个名称。 - 可选地,在
auto-form/config.tsx
中的DEFAULT_ZOD_HANDLERS
下为 zod 类型添加组件名称作为默认处理程序。
许可证
MIT
编辑推荐精选


Manus
全面超越基准的 AI Agent助手
Manus 是一款通用人工智能代理平台,能够将您的创意和想法迅速转化为实际成果。无论是定制旅行规划、深入的数据分析,还是教育支持与商业决策,Manus 都能高效整合信息,提供精准解决方案。它以直观的交互体验和领先的技术,为用户开启了一个智慧驱动、轻松高效的新时代,让每个灵感都能得到完美落地。


飞书知识问答
飞书官方推出的AI知识库 上传word pdf即可部署AI私有知识库
基于DeepSeek R1大模型构建的知识管理系统,支持PDF、Word、PPT等常见文档格式解析,实现云端与本地数据的双向同步。系统具备实时网络检索能力,可自动关联外部信息源,通过语义理解技术处理结构化与非结构化数据。免费版本提供基础知识库搭建功能,适用于企业文档管理和个人学习资料整理场景。


Trae
字节跳动发布的AI编程神器IDE
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

酷表ChatExcel
大模型驱动的Excel数据处理工具
基于大模型交互的表格处理系统,允许用户通过对话方式完成数据整理和可视化分析。系统采用机器学习算法解析用户指令,自动执行排序、公式计算和数据透视等操作,支持多种文件格式导入导出。数据处理响应速度保持在0.8秒以内,支持超过100万行数据的即时分析。


DeepEP
DeepSeek开源的专家并行通信优化框架
DeepEP是一个专为大规模分布式计算设计的通信库,重点解决专家并行模式中的通信瓶颈问题。其核心架构采用分层拓扑感知技术,能够自动识别节点间物理连接关系,优化数据 传输路径。通过实现动态路由选择与负载均衡机制,系统在千卡级计算集群中维持稳定的低延迟特性,同时兼容主流深度学习框架的通信接口。


DeepSeek
全球领先开源大模型,高效智能助手
DeepSeek是一家幻方量化创办的专注于通用人工智能的中国科技公司,主攻大模型研发与应用。DeepSeek-R1是开源的推理模型,擅长处理复杂任务且可免费商用。


KnowS
AI医学搜索引擎 整合4000万+实时更新的全球医学文献
医学领域专用搜索引擎整合4000万+实时更新的全球医学文献,通过自主研发AI模型实现精准知识检索。系统每日更新指南、中英文文献及会议资料,搜索准确率较传统工具提升80%,同时将大模型幻觉率控制在8%以下。支持临床建议生成、文献深度解析、学术报告制作等全流程科研辅助,典型用户反馈显示每周可节省医疗工作者70%时间。


Windsurf Wave 3
Windsurf Editor推出第三次重大更新Wave 3
新增模型上下文协议支持与智能编辑功能。本次更新包含五项核心改进:支持接入MCP协议扩展工具生态,Tab键智能跳转提升编码效率,Turbo模式实现自动化终端操作,图片拖拽功能优化多模态交互,以及面向付费用户的个性化图标定制。系统同步集成DeepSeek、Gemini等新模型,并通过信用点数机制实现差异化的资源调配。


腾讯元宝
腾讯自研的混元大模型AI助手
腾讯元宝是 腾讯基于自研的混元大模型推出的一款多功能AI应用,旨在通过人工智能技术提升用户在写作、绘画、翻译、编程、搜索、阅读总结等多个领域的工作与生活效率。


Grok3
埃隆·马斯克旗下的人工智能公司 xAI 推出的第三代大规模语言模型
Grok3 是由埃隆·马斯克旗下的人工智能公司 xAI 推出的第三代大规模语言模型,常被马斯克称为“地球上最聪明的 AI”。它不仅是在前代产品 Grok 1 和 Grok 2 基础上的一次飞跃,还在多个关键技术上实现了创新突破。
推荐工具精选
AI云服务特惠
懂AI专属折扣关注微信公众号
最新AI工具、AI资讯
独家AI资源、AI项目落地

微信扫一扫关注公众号