Clean, modern, and advanced AI building blocks. Copy and paste into your apps. Works with all React frameworks. Open Source. Free forever.
export function HelloWorld() {
return <h1 className="text-2xl font-bold text-center">Hello World</h1>;
}
'use client';
import * as React from 'react';
import { z } from 'zod';
import { Button } from '@/components/ui/button';
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
const exampleFormSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
message: z.string().min(1),
});
export function ExampleForm() {
const [pending, setPending] = React.useState(false);
const [state, setState] = React.useState({
defaultValues: {
name: '',
email: '',
message: '',
},
success: false,
errors: {
name: '',
email: '',
message: '',
},
});
const handleSubmit = React.useCallback(
(e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setPending(true);
const formData = new FormData(e.target as HTMLFormElement);
const data = Object.fromEntries(formData.entries());
const result = exampleFormSchema.safeParse(data);
if (!result.success) {
setState({
...state,
errors: Object.fromEntries(
Object.entries(result.error.flatten().fieldErrors).map(
([key, value]) => [key, value?.[0] ?? '']
)
) as Record<keyof typeof state.errors, string>,
});
setPending(false);
return;
}
setPending(false);
},
[state]
);
return (
<Card className="w-full max-w-sm mx-auto">
<CardHeader>
<CardTitle>How can we help?</CardTitle>
<CardDescription>
Need help with your project? We're here to assist you.
</CardDescription>
</CardHeader>
<form onSubmit={handleSubmit}>
<CardContent className="flex flex-col gap-6">
<div
className="group/field grid gap-2"
data-invalid={!!state.errors?.name}
>
<Label
htmlFor="name"
className="group-data-[invalid=true]/field:text-destructive"
>
Name <span aria-hidden="true">*</span>
</Label>
<Input
id="name"
name="name"
placeholder="Lee Robinson"
className="group-data-[invalid=true]/field:border-destructive focus-visible:group-data-[invalid=true]/field:ring-destructive"
disabled={pending}
aria-invalid={!!state.errors?.name}
aria-errormessage="error-name"
defaultValue={state.defaultValues.name}
/>
{state.errors?.name && (
<p id="error-name" className="text-destructive text-sm">
{state.errors.name}
</p>
)}
</div>
<div
className="group/field grid gap-2"
data-invalid={!!state.errors?.email}
>
<Label
htmlFor="email"
className="group-data-[invalid=true]/field:text-destructive"
>
Email <span aria-hidden="true">*</span>
</Label>
<Input
id="email"
name="email"
placeholder="leerob@acme.com"
className="group-data-[invalid=true]/field:border-destructive focus-visible:group-data-[invalid=true]/field:ring-destructive"
disabled={pending}
aria-invalid={!!state.errors?.email}
aria-errormessage="error-email"
defaultValue={state.defaultValues.email}
/>
{state.errors?.email && (
<p id="error-email" className="text-destructive text-sm">
{state.errors.email}
</p>
)}
</div>
<div
className="group/field grid gap-2"
data-invalid={!!state.errors?.message}
>
<Label
htmlFor="message"
className="group-data-[invalid=true]/field:text-destructive"
>
Message <span aria-hidden="true">*</span>
</Label>
<Textarea
id="message"
name="message"
placeholder="Type your message here..."
className="group-data-[invalid=true]/field:border-destructive focus-visible:group-data-[invalid=true]/field:ring-destructive"
disabled={pending}
aria-invalid={!!state.errors?.message}
aria-errormessage="error-message"
defaultValue={state.defaultValues.message}
/>
{state.errors?.message && (
<p id="error-message" className="text-destructive text-sm">
{state.errors.message}
</p>
)}
</div>
</CardContent>
<CardFooter>
<Button type="submit" size="sm" disabled={pending}>
{pending ? 'Sending...' : 'Send Message'}
</Button>
</CardFooter>
</form>
</Card>
);
}