# Input Otp Standard 5 - In form with validation

> OTP in Form with Validation.

A shadcn/ui block from the [@shadcnblocks](https://shadcnblocks.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcnblocks/input-otp-input-otp-standard-5).

- Page, with a live preview: https://shadcn.exchange/r/shadcnblocks/input-otp-input-otp-standard-5
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcnblocks/input-otp-input-otp-standard-5-light-34c824cdddda4d4c.png
- Registry item: https://shadcnblocks.com/r/input-otp-input-otp-standard-5.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcnblocks.com/r/input-otp-input-otp-standard-5.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@hookform/resolvers`, `react-hook-form`, `sonner`, `zod`
- Registry items: `button`, `field`, `input-otp`

## Files

### `example/input-otp/input-otp-standard-5.tsx`

```tsx
"use client";

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";

import { Button } from "@/components/ui/button";
import { Controller } from "react-hook-form";

import {
  Field,
  FieldDescription,
  FieldError,
  FieldLabel,
} from "@/components/ui/field";
import {
  InputOTP,
  InputOTPGroup,
  InputOTPSeparator,
  InputOTPSlot,
} from "@/components/ui/input-otp";

export const title = "OTP in Form with Validation";

const formSchema = z.object({
  pin: z.string().min(6, {
    message: "Your one-time password must be 6 characters.",
  }),
});

const Example = () => {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      pin: "",
    },
  });

  function onSubmit(values: z.infer<typeof formSchema>) {
    toast.success(`You submitted the following values: ${values.pin}`);
  }

  return (
    <div className="w-full max-w-md">
      <form className="space-y-6" onSubmit={form.handleSubmit(onSubmit)}>
        <Controller
          control={form.control}
          name="pin"
          render={({ field, fieldState }) => (
            <Field data-invalid={fieldState.invalid}>
              <FieldLabel>One-Time Password</FieldLabel>
              <InputOTP maxLength={6} {...field}>
                <InputOTPGroup>
                  <InputOTPSlot className="bg-background" index={0} />
                  <InputOTPSlot className="bg-background" index={1} />
                  <InputOTPSlot className="bg-background" index={2} />
                </InputOTPGroup>
                <InputOTPSeparator />
                <InputOTPGroup>
                  <InputOTPSlot className="bg-background" index={3} />
                  <InputOTPSlot className="bg-background" index={4} />
                  <InputOTPSlot className="bg-background" index={5} />
                </InputOTPGroup>
              </InputOTP>
              <FieldDescription>
                Please enter the one-time password sent to your phone.
              </FieldDescription>
              {fieldState.invalid && <FieldError errors={[fieldState.error]} />}
            </Field>
          )}
        />
        <Button type="submit">Submit</Button>
      </form>
    </div>
  );
};

export default Example;
```
