
zod schema marking some fields optional alongside required ones.
@shadcnblocks
example/form/form-multi-field-5.tsx
"use client";
import { zodResolver } from "@hookform/resolvers/zod";
import { Controller, useForm } from "react-hook-form";
import { z } from "zod";
import { Button } from "@/components/ui/button";
import {
Field,
FieldDescription,
FieldError,
FieldGroup,
FieldLabel,
} from "@/components/ui/field";
import { Input } from "@/components/ui/input";
export const title = "Form with Optional Fields";
const formSchema = z.object({
firstName: z.string().min(2, {
message: "First name must be at least 2 characters.",
}),
lastName: z.string().min(2, {
message: "Last name must be at least 2 characters.",
}),
email: z.string().email("Please enter a valid email address."),
company: z.string().optional(),
website: z.string().url().optional().or(z.literal("")),
});
const Example = () => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
firstName: "",
lastName: "",
email: "",
company: "",
website: "",
},
});
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values);
}
return (
<div className="w-full max-w-md">
<form className="space-y-4" onSubmit={form.handleSubmit(onSubmit)}>
<FieldGroup>
<div className="grid grid-cols-2 gap-4">
<Controller
name="firstName"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor={field.name}>First Name</FieldLabel>
<Input
{...field}
id={field.name}
aria-invalid={fieldState.invalid}
className="bg-background"
placeholder="John"
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
<Controller
name="lastName"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor={field.name}>Last Name</FieldLabel>
<Input
{...field}
id={field.name}
aria-invalid={fieldState.invalid}
className="bg-background"
placeholder="Doe"
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
</div>
<Controller
name="email"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor={field.name}>Email</FieldLabel>
<Input
{...field}
id={field.name}
aria-invalid={fieldState.invalid}
className="bg-background"
placeholder="john@example.com"
type="email"
/>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
<Controller
name="company"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor={field.name}>Company (Optional)</FieldLabel>
<Input
{...field}
id={field.name}
aria-invalid={fieldState.invalid}
className="bg-background"
placeholder="Acme Inc"
/>
<FieldDescription>Where do you work?</FieldDescription>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
<Controller
name="website"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor={field.name}>Website (Optional)</FieldLabel>
<Input
{...field}
id={field.name}
aria-invalid={fieldState.invalid}
className="bg-background"
placeholder="https://example.com"
type="url"
/>
<FieldDescription>
Your personal or company website.
</FieldDescription>
{fieldState.invalid && (
<FieldError errors={[fieldState.error]} />
)}
</Field>
)}
/>
</FieldGroup>
<Button type="submit">Save</Button>
</form>
</div>
);
};
export default Example;




























