NextJS+Zod:如何让shadcn Form验证通过时输入框变绿
解决shadcn Form组件验证通过时添加绿色样式的方法
shadcn的Form组件基于React Hook Form实现,我们可以借助React Hook Form提供的表单状态,判断输入框验证状态后动态添加自定义样式类。
步骤1:定义验证通过的样式类
先在项目的CSS文件中添加自定义绿色样式:
.input-success { border-color: #10b981; /* 绿色边框 */ box-shadow: 0 0 0 1px #10b981; /* 可选:添加绿色外发光效果 */ }
步骤2:在FormField中判断验证状态并添加类
通过FormField的children函数,获取表单的touchedFields(是否触碰过输入框)、errors(是否有验证错误)以及输入框的值,判断是否满足验证通过的条件,再动态给FormInput添加自定义类。
示例代码:
import { Form, FormField, FormInput, FormLabel, FormMessage } from '@/components/ui/form' import { useForm } from 'react-hook-form' type FormValues = { email: string password: string } export function AuthForm() { const form = useForm<FormValues>() return ( <Form {...form}> <form onSubmit={form.handleSubmit((values) => console.log(values))} className="space-y-6"> {/* 邮箱输入框 */} <FormField control={form.control} name="email" rules={{ required: '邮箱不能为空', pattern: { value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: '请输入有效的邮箱格式' } }} children={({ field, formState }) => { // 验证通过条件:已触碰输入框 + 无错误 + 输入内容不为空 const isSuccess = formState.touchedFields.email && !formState.errors.email && field.value.trim() !== '' return ( <div className="space-y-2"> <FormLabel htmlFor="email">邮箱</FormLabel> <FormInput id="email" {...field} className={isSuccess ? 'input-success' : ''} /> <FormMessage /> </div> ) }} /> {/* 密码输入框 */} <FormField control={form.control} name="password" rules={{ required: '密码不能为空', minLength: { value: 6, message: '密码至少6位' } }} children={({ field, formState }) => { const isSuccess = formState.touchedFields.password && !formState.errors.password && field.value.trim() !== '' return ( <div className="space-y-2"> <FormLabel htmlFor="password">密码</FormLabel> <FormInput id="password" type="password" {...field} className={isSuccess ? 'input-success' : ''} /> <FormMessage /> </div> ) }} /> <button type="submit" className="w-full py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">提交</button> </form> </Form> ) }
关键逻辑说明
formState.touchedFields[字段名]:确保输入框已经被用户触碰过(比如点击输入后离开),避免页面刚加载就显示绿色样式!formState.errors[字段名]:确认当前输入没有验证错误field.value.trim() !== '':确保输入框有实际内容(可选,若你的业务允许空值验证通过,可去掉此判断)
扩展:封装可复用的成功状态输入框
如果多个输入框都需要这个效果,可以封装一个自定义组件来复用逻辑:
import { FormInput, FormInputProps } from '@/components/ui/form' import { FieldValues, UseFormReturn } from 'react-hook-form' type SuccessFormInputProps<T extends FieldValues> = FormInputProps & { form: UseFormReturn<T> fieldName: keyof T } export function SuccessFormInput<T extends FieldValues>({ form, fieldName, ...props }: SuccessFormInputProps<T>) { const { touchedFields, errors } = form.formState const fieldValue = form.watch(fieldName) const isSuccess = touchedFields[fieldName] && !errors[fieldName] && String(fieldValue).trim() !== '' return <FormInput {...props} className={`${isSuccess ? 'input-success' : ''} ${props.className || ''}`} /> }
使用时只需传入表单实例和字段名:
<FormField control={form.control} name="username" rules={{ required: '用户名不能为空' }} children={({ field }) => ( <div className="space-y-2"> <FormLabel htmlFor="username">用户名</FormLabel> <SuccessFormInput form={form} fieldName="username" id="username" {...field} /> <FormMessage /> </div> )} />
内容的提问来源于stack exchange,提问作者Beres
相关产品推荐
相关产品推荐

