Skip to content

shadcn.io is an independent project built on shadcn/ui

Free

OTP with Loading State Input OTP for React

A six-digit code field that shows a spinner and Verifying code... once all six digits are in.

Six boxes in two groups of three. After a full code, a spinner and the words Verifying code... appear under the boxes.

Show the spinner while the check is in flight so the pause does not look like a failure. A Button label can say the same thing if you submit by hand. In React, Base UI does not verify the code.

Preview

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.
Use email insteadNo credit card

Anatomy

Input OTP anatomy: root, group, separator, slot

Usage

<div className="flex flex-col gap-2">
  <InputOTP
    maxLength={6}
    onChange={handleValueChange}
    onComplete={handleComplete}
    value={value}
  >
    <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>
  {isVerifying ? (
    <div className="flex items-center gap-2 text-sm" role="status">
      <Spinner />
      <span>Verifying code...</span>
    </div>
  ) : null}
</div>

FAQ

What starts the verification?

The field's completion callback, which fires once every slot is filled. onComplete fires when the code reaches maxLength.

How is the loading state shown?

A row with our Spinner and the text Verifying code..., rendered only while verifying. The row has role status, so the message is announced.

Is there a real request?

No. A two-second timer stands in for it. Replace it with your API call and turn the loading state off when it settles.

Should the field be locked while verifying?

Often, yes: pass disabled from the same loading state so the code can't change mid-request. The Success State example disables the field once the code is accepted.

How do I show the result?

Follow the loading state with an error, as the Error State example does, or a confirmation, as the Success State example does.

How is the value kept?

In state, written on every change. The value is one string, and onChange receives the next string.

API Reference

Input OTP

Sets maxLength={6}, onChange={handleValueChange}, onComplete={handleComplete}, value={value}, index={0} and index={1}. The rest is on the Input OTP page.

Spinner

No extra props in this demo. The rest is on the Spinner page.