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.
Xem trước
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.
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.
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ên | Kiểu | Giá trị | Mặc định | Mô tả |
|---|---|---|---|---|
| length | number | - | 6 | Số slot. Các mã phổ biến nhất là 4 và 6 chữ số. |
| pattern | enum | numeric | alphanumeric | numeric | numeric chỉ nhận chữ số (inputmode numeric); alphanumeric cũng nhận chữ cái. |
| value | string | - | - | Giá trị mã controlled. Ký tự ngoài pattern và phần vượt quá length bị lọc. |
| defaultValue | string | - | - | Mã ban đầu cho input uncontrolled. |
| onValueChange | function | - | - | Được gọi với mã đã lọc trên mỗi lần đổi. |
| onComplete | function | - | - | Đượ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. |
| size | enum | md | lg | xl | lg | 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. |
| disabled | boolean | - | false | Làm input disabled; các slot nhận nền và chữ disabled. |
| invalid | boolean | - | false | Mọi slot nhận viền danger, input đặt aria-invalid. |
| required | boolean | - | false | Thuộc tính required chuẩn trên input. |
| name | string | - | - | Tên field của form, được form bao ngoài gửi đi. |
Slot
| Tên | Bắt buộc | Mô tả |
|---|---|---|
| value | không | Giá trị mã controlled hoặc uncontrolled, đã lọc theo pattern và length. |
Cấu tạo
| Phần | Mô tả |
|---|---|
| root | Dả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). |
| slot | Mộ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. |
| caret | Thanh accent trong slot kế tiếp cần điền khi đang focus, thay cho caret của input trong suốt. |
| input | Input 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ím | Hành động |
|---|---|
| 0-9 / A-Z | Điền slot trống kế tiếp. Ký tự ngoài pattern bị bỏ. |
| Backspace | Xóa ký tự nhập cuối cùng. |
| Left / Right | Di chuyển caret văn bản bên trong mã, hành vi input gốc. |
| Paste | Dá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-inputChạ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.