标准栈
每个 FormField 都应有 FormMessage。在 frontend/package.json 中声明 react-hook-form、zod、@hookform/resolvers。
- Form — 展开 useForm 返回值
- FormField — 通过 render prop 绑定 control + name
- FormItem / FormLabel / FormControl / FormMessage
- zod schema + zodResolver
TSXform
1import { zodResolver } from "@hookform/resolvers/zod";
2import {
3 Button,
4 Form,
5 FormControl,
6 FormField,
7 FormItem,
8 FormLabel,
9 FormMessage,
10 Input,
11} from "@quan-erp/shared-ui";
12import { useForm } from "react-hook-form";
13import { z } from "zod";
14
15const schema = z.object({
16 email: z.string().min(1, "Email is required").email("Enter a valid email"),
17 password: z.string().min(6, "Password must be at least 6 characters"),
18});
19
20type FormValues = z.infer<typeof schema>;
21
22export function ExampleForm({ onSubmit }: { onSubmit: (v: FormValues) => void }) {
23 const form = useForm<FormValues>({
24 resolver: zodResolver(schema),
25 defaultValues: { email: "", password: "" },
26 });
27
28 return (
29 <Form {...form}>
30 <form className="space-y-3" onSubmit={form.handleSubmit(onSubmit)}>
31 <FormField
32 control={form.control}
33 name="email"
34 render={({ field }) => (
35 <FormItem>
36 <FormLabel>Email</FormLabel>
37 <FormControl>
38 <Input type="email" autoComplete="email" {...field} />
39 </FormControl>
40 <FormMessage />
41 </FormItem>
42 )}
43 />
44 <Button type="submit">Submit</Button>
45 </form>
46 </Form>
47 );
48}