You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Next.js14中结合ShadcnUI与NextUI:解决表单错误提示失效问题

在Shadcn UI Form中正确集成NextUI Input组件

问题根源

  1. 错误状态未结合字段触摸状态(isTouched):react-hook-form默认仅在字段被触摸或表单提交后才暴露错误信息,未触发时不会显示错误提示。
  2. useFormField属性解构不完整:仅获取error不足以控制错误显示逻辑,需同时结合isTouched判断。
  3. 表单验证模式配置缺失:未明确设置验证触发时机,可能导致提交时未强制验证所有字段。

修正方案

1. 完善react-hook-form配置(可选但推荐)

在useForm中添加mode: "onSubmit",确保表单提交时强制触发所有字段验证:

import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";

const FormSchema = z.object({
  email: z.string().min(1, "Email is required").email("Invalid email"),
  password: z
    .string()
    .min(1, "Password is required")
    .min(8, "Password must have at least 8 characters"),
});

const form = useForm<z.infer<typeof FormSchema>>({
  resolver: zodResolver(FormSchema),
  defaultValues: {
    email: "",
    password: "",
  },
  mode: "onSubmit", // 提交时触发全量验证
});

2. 正确绑定NextUI Input与表单状态

在FormField的render回调中,完整解构useFormField返回值,将isInvalid设置为!!(error && isTouched),确保错误提示仅在合理时机显示:

import { Form, FormField } from "@/components/ui/form";
import { Input } from "@nextui-org/react";
import { useFormField } from "@/components/ui/form";

// 假设你已定义onSubmit函数
const onSubmit = (values: z.infer<typeof FormSchema>) => {
  console.log("提交数据:", values);
  // 后续业务逻辑:如API请求等
};

// 表单组件
<Form {...form}>
  <form onSubmit={form.handleSubmit(onSubmit)} className="w-full space-y-4">
    {/* Email字段 */}
    <FormField
      control={form.control}
      name="email"
      render={({ field }) => {
        const { error, isTouched } = useFormField();
        return (
          <Input
            size="md"
            isRequired
            type="email"
            label="Email"
            placeholder="Enter your email"
            errorMessage={error?.message}
            isInvalid={!!(error && isTouched)} // 结合错误与触摸状态
            {...field}
          />
        );
      }}
    />

    {/* Password字段(同逻辑) */}
    <FormField
      control={form.control}
      name="password"
      render={({ field }) => {
        const { error, isTouched } = useFormField();
        return (
          <Input
            size="md"
            isRequired
            type="password"
            label="Password"
            placeholder="Enter your password"
            errorMessage={error?.message}
            isInvalid={!!(error && isTouched)}
            {...field}
          />
        );
      }}
    />

    <button type="submit" className="w-full bg-blue-600 text-white py-2 rounded-md">
      Submit
    </button>
  </form>
</Form>

3. 关键逻辑说明

  • isTouched的作用:避免页面初始化时就显示错误提示,提升用户体验;若希望提交后无论是否触摸都显示错误,可将isInvalid改为!!error。
  • 类型安全优化:避免使用any类型,可给field添加明确类型:{ field: ControllerRenderProps<z.infer<typeof FormSchema>, "email"> }(需从react-hook-form导入ControllerRenderProps)。
  • NextUI属性映射:NextUI的Input会在isInvalid为true时自动显示errorMessage,无需额外手动控制显示逻辑。

内容的提问来源于stack exchange,提问作者Viet Quang Fresher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 22:34:52