p-form-2

PreviousNext

Form with zod validation

Docs
cossblock

Preview

Loading preview…
registry/default/particles/p-form-2.tsx
"use client";

import * as React from "react";
import { z } from "zod";

import { Button } from "@/registry/default/ui/button";
import { Field, FieldError, FieldLabel } from "@/registry/default/ui/field";
import { Form } from "@/registry/default/ui/form";
import { Input } from "@/registry/default/ui/input";

const schema = z.object({
  age: z.coerce
    .number({ message: "Please enter a number." })
    .positive({ message: "Number must be positive." }),
  name: z.string().min(1, { message: "Please enter a name." }),
});

type Errors = Record<string, string | string[]>;

async function submitForm(event: React.FormEvent<HTMLFormElement>) {
  event.preventDefault();

  const formData = new FormData(event.currentTarget);
  const result = schema.safeParse(Object.fromEntries(formData));

  if (!result.success) {
    const { fieldErrors } = z.flattenError(result.error);
    return { errors: fieldErrors as Errors };
  }

  return {
    errors: {} as Errors,
  };
}

export default function Particle() {
  const [loading, setLoading] = React.useState(false);
  const [errors, setErrors] = React.useState<Errors>({});

  const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    setLoading(true);
    const response = await submitForm(event);
    await new Promise((r) => setTimeout(r, 800));
    setErrors(response.errors);
    setLoading(false);
    if (Object.keys(response.errors).length === 0) {
      alert(
        `Name: ${String(formData.get("name") || "")}\nAge: ${String(
          formData.get("age") || "",
        )}`,
      );
    }
  };

  return (
    <Form className="max-w-64" errors={errors} onSubmit={onSubmit}>
      <Field name="name">
        <FieldLabel>Name</FieldLabel>
        <Input disabled={loading} placeholder="Enter name" />
        <FieldError />
      </Field>
      <Field name="age">
        <FieldLabel>Age</FieldLabel>
        <Input disabled={loading} placeholder="Enter age" />
        <FieldError />
      </Field>
      <Button disabled={loading} type="submit">
        Submit
      </Button>
    </Form>
  );
}

Installation

npx shadcn@latest add @coss/p-form-2

Usage

import { PForm2 } from "@/components/p-form-2"
<PForm2 />