Chuyển tới nội dung

Pro đang mở bán trước. Cài đặt mở từ tháng 1/2027. Xem Pro

Component

OtpInput

Field mã một lần hiện thành các slot bằng nhau, cho mã xác minh email và SMS. Đây là một input thật với autocomplete one-time-code, không phải một input cho mỗi chữ số, nên nền tảng điền được mã từ một tin nhắn (DECISIONS 2026-10-15). Các slot là một lớp trực quan; input mang giá trị, việc điền và mọi hành vi bàn phím. Dùng Input cho văn bản tự do.

  • npm: 1 trực tiếp, 2 tổng
  • registry: 2 trực tiếp, 2 tổng

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

  • Nhập một mã xác minh ngắn từ email hoặc SMS, kiểm từng chữ số hoặc cả mã.
  • Một mã mà nền tảng điền được từ tin nhắn, qua autocomplete one-time-code của input duy nhất.

Khi nào không dùng

  • Một mã định danh dài hơn mà người dùng sao chép trọn vẹn, chẳng hạn API key hoặc số thẻ. Dùng Input.
  • Một số lượng mà người dùng chỉnh. Dùng NumberInput.
  • Văn bản tự do. Dùng Input.

Biến thể

pattern

numeric chỉ nhận chữ số (inputmode numeric); alphanumeric cũng nhận chữ cái.

  • 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

Kích thước slot và khoảng cách. lg theo mặc định (44px trên cảm ứng), md trong form đặc, xl cho bước xác minh hero. Không có sm: một ô mã 28px quá nhỏ để đọc và chạm.

  • md

  • lgmặc định

  • 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-md">Mã xác minh</FieldLabel>
  <FieldControl>
    <OtpInput id="preview-otp-input-size-md" 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" 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ụ

Mã xác minh

Mã sáu chữ số, được xác minh khi đủ.

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

<Field>
  <FieldLabel>Mã xác minh</FieldLabel>
  <FieldControl>
    <OtpInput length={6} onComplete={verifyCode} />
  </FieldControl>
</Field>

Mã bị từ chối

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

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

Bốn chữ số, ưu tiên cảm ứng

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

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

Nên và không nên

Nên

  • Dùng bên trong Field để label và lỗi được nối, và đặt invalid khi server từ chối mã.
  • Xác minh trong onComplete, và giữ field enabled để người dùng sửa mã bị từ chối.
  • Giữ lg mặc định, để mỗi slot là 44px hoặc lớn hơn trên cảm ứng; dùng xl cho bước xác minh hero.

Không nên

  • Đừng dựng một input cho mỗi chữ số; việc nền tảng điền từ tin nhắn xác minh cần input duy nhất.
  • Đừng dùng cho mã định danh mà người dùng sao chép trọn vẹn, chẳng hạn API key; dùng Input.
  • Đừng autofocus trên các trang mà người dùng phải đọc hướng dẫn trước.

Props

TênKiểuGiá trịMặc địnhMô tả
lengthnumber-6Số slot. Các mã phổ biến nhất là 4 và 6 chữ số.
patternenumnumeric | alphanumericnumericnumeric chỉ nhận chữ số (inputmode numeric); alphanumeric cũng nhận chữ cái.
valuestring--Giá trị mã controlled. Ký tự ngoài pattern và phần vượt quá length bị lọc.
defaultValuestring--Mã ban đầu cho input uncontrolled.
onValueChangefunction--Được gọi với mã đã lọc trên mỗi lần đổi.
onCompletefunction--Được gọi một lần mỗi khi mã đạt đủ độ dài trong lúc người dùng gõ, để việc xác minh có thể bắt đầu.
sizeenummd | lg | xllgKích thước slot và khoảng cách. lg theo mặc định (44px trên cảm ứng), md trong form đặc, xl cho bước xác minh hero. Không có sm: một ô mã 28px quá nhỏ để đọc và chạm.
disabledboolean-falseLàm input disabled; các slot nhận nền và chữ disabled.
invalidboolean-falseMọi slot nhận viền danger, input đặt aria-invalid.
requiredboolean-falseThuộc tính required chuẩn trên input.
namestring--Tên field của form, được form bao ngoài gửi đi.

Slot

TênBắt buộcMô tả
valuekhôngGiá trị mã controlled hoặc uncontrolled, đã lọc theo pattern và length.

Cấu tạo

PhầnMô tả
rootDải: một hàng flex relative, mang khoảng cách của size và vẽ vòng focus trên slot active (has-input-focus-visible).
slotMột ô mã vuông, kích thước theo size-element để các size cảm ứng được áp dụng. Hiện ký tự, hoặc một thanh caret accent khi đó là slot kế tiếp cần điền trong lúc focus. Khi đang focus, slot active (slot kế tiếp cần điền, hoặc slot cuối khi mã đã đầy) mang data-active và vòng focus. aria-hidden.
caretThanh accent trong slot kế tiếp cần điền khi đang focus, thay cho caret của input trong suốt.
inputInput văn bản duy nhất phủ lên dải: chữ và caret trong suốt trên các slot, autocomplete one-time-code, inputmode numeric hoặc text. Mang value, name, disabled, required và aria-invalid.

Khả năng truy cập

Role: textbox

PhímHành động
0-9 / A-ZĐiền slot trống kế tiếp. Ký tự ngoài pattern bị bỏ.
BackspaceXóa ký tự nhập cuối cùng.
Left / RightDi chuyển caret văn bản bên trong mã, hành vi input gốc.
PasteDán mã; ký tự ngoài pattern bị bỏ, phần còn lại điền từ đầu.
  • Các slot là aria-hidden; trình đọc màn hình thông báo một textbox với cả mã, không phải một vùng cho mỗi chữ số.
  • Việc nền tảng điền từ SMS xác minh hoạt động vì trình duyệt thấy một input duy nhất với autocomplete one-time-code.
  • Dùng bên trong Field để label và lỗi được nối. aria-invalid được đặt trên input khi invalid là 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.