Chuyển tới nội dung
Component

OtpInput

A one-time code field shown as equal slots, for email and SMS verification codes. It is one real input with autocomplete one-time-code, not one input per digit, so the platform can fill the code from a message (DECISIONS 2026-10-15). The slots are a visual layer; the input carries the value, the fill and every keyboard behavior. Use Input for free text.

Xem trước

Props

  • length
  • pattern
  • size
  • disabled
  • invalid
  • required
  • name
import { Field, FieldControl, FieldLabel } from "@/components/ui/field"
import { OtpInput } from "@/components/ui/otp-input"

<Field className="w-full max-w-sm" invalid={false}>
  <FieldLabel htmlFor="preview-otp-input">Mã xác minh</FieldLabel>
  <FieldControl>
    <OtpInput id="preview-otp-input" length={6} />
  </FieldControl>
</Field>

Cách dùng

Khi nào dùng

  • Enter a short verification code from an email or SMS, checked digit by digit or in full.
  • A code the platform can fill from the message, through the single input's autocomplete one-time-code.

Khi nào không dùng

  • A longer identifier the user copies in full, such as an API key or a card number. Use Input.
  • A numeric quantity the user adjusts. Use NumberInput.
  • Free-form text. Use Input.

Biến thể

pattern

numeric accepts digits only (inputmode numeric); alphanumeric also accepts letters.

  • numericmặc định

  • alphanumeric

import { Field, FieldControl, FieldLabel } from "@/components/ui/field"
import { OtpInput } from "@/components/ui/otp-input"

<Field className="w-full max-w-sm" invalid={false}>
  <FieldLabel htmlFor="preview-otp-input-pattern-numeric">Mã xác minh</FieldLabel>
  <FieldControl>
    <OtpInput id="preview-otp-input-pattern-numeric" length={6} />
  </FieldControl>
</Field>
<Field className="w-full max-w-sm" invalid={false}>
  <FieldLabel htmlFor="preview-otp-input-pattern-alphanumeric">Mã xác minh</FieldLabel>
  <FieldControl>
    <OtpInput id="preview-otp-input-pattern-alphanumeric" pattern="alphanumeric" length={6} />
  </FieldControl>
</Field>

size

Slot size and gap. md by default, lg on touch-first screens, xl for a hero verification step.

  • sm

  • mdmặc định

  • lg

  • xl

import { Field, FieldControl, FieldLabel } from "@/components/ui/field"
import { OtpInput } from "@/components/ui/otp-input"

<Field className="w-full max-w-sm" invalid={false}>
  <FieldLabel htmlFor="preview-otp-input-size-sm">Mã xác minh</FieldLabel>
  <FieldControl>
    <OtpInput id="preview-otp-input-size-sm" size="sm" length={6} />
  </FieldControl>
</Field>
<Field className="w-full max-w-sm" invalid={false}>
  <FieldLabel htmlFor="preview-otp-input-size-md">Mã xác minh</FieldLabel>
  <FieldControl>
    <OtpInput id="preview-otp-input-size-md" length={6} />
  </FieldControl>
</Field>
<Field className="w-full max-w-sm" invalid={false}>
  <FieldLabel htmlFor="preview-otp-input-size-lg">Mã xác minh</FieldLabel>
  <FieldControl>
    <OtpInput id="preview-otp-input-size-lg" size="lg" length={6} />
  </FieldControl>
</Field>
<Field className="w-full max-w-sm" invalid={false}>
  <FieldLabel htmlFor="preview-otp-input-size-xl">Mã xác minh</FieldLabel>
  <FieldControl>
    <OtpInput id="preview-otp-input-size-xl" size="xl" length={6} />
  </FieldControl>
</Field>

Ví dụ

Verification code

A six-digit code, verified once complete.

const [code, setCode] = React.useState("")
import { Field, FieldControl } from "@/components/ui/field"
import { OtpInput } from "@/components/ui/otp-input"

const [code, setCode] = React.useState("")
<Field label="Verification code">
  <FieldControl>
    <OtpInput length={6} value={code} onValueChange={setCode} />
  </FieldControl>
</Field>

Rejected code

import { OtpInput } from "@/components/ui/otp-input"

<OtpInput length={6} defaultValue="123456" invalid />

Four digits, touch-first

import { OtpInput } from "@/components/ui/otp-input"

<OtpInput length={4} size="xl" />

Nên và không nên

Nên

  • Use inside Field so the label and error are linked, and set invalid when the server rejects the code.
  • Verify in onComplete, and keep the field enabled so the user can correct a rejected code.
  • Use lg or xl on touch-first screens; each slot is then 44px or larger.

Không nên

  • Do not build one input per digit; the platform fill from a verification message needs the single input.
  • Do not use for identifiers the user copies in full, such as an API key; use Input.
  • Do not autofocus on pages where the user must read instructions first.

Props

TênKiểuGiá trịMặc địnhMô tả
lengthnumber-6Number of slots. The most common codes are 4 and 6 digits.
patternenumnumeric | alphanumericnumericnumeric accepts digits only (inputmode numeric); alphanumeric also accepts letters.
valuestring--Controlled code value. Characters outside the pattern and beyond length are filtered.
defaultValuestring--Initial code for the uncontrolled input.
onValueChangefunction--Called with the filtered code on every change.
onCompletefunction--Called once each time the code reaches full length while the user types, so verification can start.
sizeenumsm | md | lg | xlmdSlot size and gap. md by default, lg on touch-first screens, xl for a hero verification step.
disabledboolean-falseDisables the input; the slots take the disabled fill and text.
invalidboolean-falseEvery slot takes the danger border, the input sets aria-invalid.
requiredboolean-falseStandard required attribute on the input.
namestring--Form field name, submitted by the surrounding form.

Slot

TênBắt buộcMô tả
valuekhôngControlled or uncontrolled code value, filtered to the pattern and length.

Cấu tạo

PhầnMô tả
rootThe strip: a relative flex row that carries the focus ring (has-input-focus-visible) and the size gap.
slotOne square code cell, sized by size-element so touch sizes apply. Shows the character, or an accent caret bar when it is the next slot to fill while focused. aria-hidden.
caretThe accent bar in the next slot to fill while focused, in place of the transparent input's caret.
inputThe single text input covering the strip: transparent text and caret over the slots, autocomplete one-time-code, inputmode numeric or text. Carries the value, name, disabled, required and aria-invalid.

Khả năng truy cập

Role: textbox

PhímHành động
0-9 / A-ZFill the next empty slot. Characters outside the pattern are dropped.
BackspaceDelete the last entered character.
Left / RightMove the text caret inside the code, native input behavior.
PastePaste the code; characters outside the pattern are dropped, the rest fill from the start.
  • The slots are aria-hidden; screen readers announce one textbox with the whole code, not one region per digit.
  • The platform fill from a verification SMS works because the browser sees a single input with autocomplete one-time-code.
  • Use inside Field so the label and error are linked. aria-invalid is set on the input when invalid is true.

Cài đặt

npx werewolf-ui add otp-input

Chạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.