# V otp field 14

> Resend countdown timer

A shadcn/ui block from the [@cnippet](https://ui.cnippet.dev/) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/cnippet/v-otp-field-14).

- Page, with a live preview: https://shadcn.exchange/r/cnippet/v-otp-field-14
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/cnippet/v-otp-field-14-light-4bd83a3f0e086744.png
- Registry item: https://ui.cnippet.dev/r/v-otp-field-14.json
- Categories: input otp
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ui.cnippet.dev/r/v-otp-field-14.json
```

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

## Dependencies

- Registry items: `@cnippet/otp-field`

## Files

### `registry/default/variants/v-otp-field-14.tsx`

```tsx
"use client";

import { CheckCircle2Icon } from "lucide-react";
import { useState } from "react";
import {
  Field,
  FieldDescription,
  FieldError,
  FieldLabel,
} from "@/registry/default/ui/field";
import { OTPField, OTPFieldInput } from "@/registry/default/ui/otp-field";

const VALID_CODE = "246810";
const OTP_LENGTH = 6;

const OTP_SLOT_KEYS = Array.from(
  { length: OTP_LENGTH },
  (_, i) => `otp-slot-${i}`,
);

export function Pattern() {
  const [value, setValue] = useState("");
  const isComplete = value.length === OTP_LENGTH;
  const isValid = isComplete && value === VALID_CODE;
  const isInvalid = isComplete && value !== VALID_CODE;

  return (
    <Field className="items-center">
      <FieldLabel>Verification code</FieldLabel>
      {isValid ? (
        <div className="flex items-center gap-2 py-1 text-green-600 text-sm">
          <CheckCircle2Icon aria-hidden="true" className="size-4" />
          Identity verified
        </div>
      ) : (
        <OTPField length={OTP_LENGTH} onValueChange={setValue} value={value}>
          {OTP_SLOT_KEYS.map((slotKey, index) => (
            <OTPFieldInput
              aria-invalid={isInvalid || undefined}
              aria-label={`Character ${index + 1} of ${OTP_LENGTH}`}
              key={slotKey}
            />
          ))}
        </OTPField>
      )}
      {isInvalid && <FieldError>Incorrect code. Please try again.</FieldError>}
      {!isComplete && !isValid && (
        <FieldDescription>
          Enter code{" "}
          <code className="font-mono text-foreground">{VALID_CODE}</code> to
          verify.
        </FieldDescription>
      )}
    </Field>
  );
}
```
