Components
Loading preview...
'use client'
import { useForm } from '@tanstack/react-form'
import { toast } from 'sonner'
import * as z from 'zod'
import { Button } from '@/components/ui/button'
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
import {
Field,
FieldError,
FieldGroup,
FieldLabel,
} from '@/components/ui/field-1'
import { Input } from '@/components/ui/input'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
const departments = [
{ value: 'design', label: 'Design' },
{ value: 'engineering', label: 'Engineering' },
{ value: 'marketing', label: 'Marketing' },
{ value: 'support', label: 'Support' },
] as const
const formSchema = z.object({
name: z.string().min(1, 'Enter your name.'),
department: z.string().min(1, 'Select a department.'),
})
export function Dialog20() {
const form = useForm({
defaultValues: {
name: '',
department: '',
},
validators: {
onSubmit: formSchema,
},
onSubmit: async ({ value }) => {
const dept =
departments.find((item) => item.value === value.department)?.label ??
value.department
toast.success('Request submitted', {
description: `${value.name} · ${dept}`,
})
},
})
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">New request (TanStack)</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-md">
<form
id="dialog-20-tanstack-form"
onSubmit={(e) => {
e.preventDefault()
form.handleSubmit()
}}
className="flex flex-col gap-6"
>
<DialogHeader>
<DialogTitle>Submit a request</DialogTitle>
<DialogDescription>
TanStack Form with Zod onSubmit validation inside a dialog.
</DialogDescription>
</DialogHeader>
<FieldGroup>
<form.Field name="name">
{(field) => {
const isInvalid =
field.state.meta.isTouched && !field.state.meta.isValid
return (
<Field data-invalid={isInvalid}>
<FieldLabel htmlFor={field.name}>Your name</FieldLabel>
<Input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
placeholder="Felipe Menezes"
aria-invalid={isInvalid}
/>
{isInvalid && (
<FieldError errors={field.state.meta.errors} />
)}
</Field>
)
}}
</form.Field>
<form.Field name="department">
{(field) => {
const isInvalid =
field.state.meta.isTouched && !field.state.meta.isValid
return (
<Field data-invalid={isInvalid}>
<FieldLabel htmlFor={field.name}>Department</FieldLabel>
<Select
value={field.state.value}
onValueChange={(value) => {
field.handleChange(value)
field.handleBlur()
}}
>
<SelectTrigger
id={field.name}
className="w-full"
aria-invalid={isInvalid}
>
<SelectValue placeholder="Select department" />
</SelectTrigger>
<SelectContent className="z-[102]">
<SelectGroup>
{departments.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
{isInvalid && (
<FieldError errors={field.state.meta.errors} />
)}
</Field>
)
}}
</form.Field>
</FieldGroup>
<DialogFooter>
<DialogClose asChild>
<Button type="button" variant="outline">
Cancel
</Button>
</DialogClose>
<Button type="submit">Submit</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
)
}
export default Dialog20Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...