Input OTP
Slots für Einmalcodes, die Tippen, Einfügen und SMS-Autofill annehmen, mit einer optionalen Animation, die Codes kaskadierend einblendet, und einem Status für die Überprüfung.
Type or paste 123456 to pass. Anything else fails.
pnpm dlx shadcn@latest add https://hextaui.com/r/input-otp.jsonFügt die Komponente, die HextaUI-Theme-Tokens und alle HextaUI-Komponenten hinzu, von denen sie abhängt.
Füge die Theme-Tokens zu deinem globalen CSS hinzu, falls du das noch nicht getan hast.
Installiere die Abhängigkeiten.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnKopiere den folgenden Code und füge ihn in dein Projekt ein.
components/ui/input-otp.tsx lib/motion.ts Passe die Importpfade an dein Projekt-Setup an.
Rendere pro Zeichen ein <InputOTPSlot /> und setze length auf dieselbe Zahl. Slots finden ihre Position selbst, es gibt also keine index-Prop, die synchron gehalten werden muss.
Verbunden
Das Standard-Aussehen. Jede <InputOTPGroup /> verbindet ihre Slots zu einem Streifen mit gemeinsamen Kanten.
Getrennt
variant="separate" gibt jedem Slot eine eigene abgerundete Box mit Abstand dazwischen.
Größen
sm, default und lg entsprechen den Höhen von Input und Button. Auf Touchscreens wächst jede Größe auf mindestens 44 px mit einer 16-px-Schrift.
Animiert
animated ist standardmäßig aus. Damit steigen getippte Zeichen ein, gelöschte sinken heraus, während die übrigen nachrücken, und ein ganzer Code aus Autofill, Einfügen oder deinem eigenen State kaskadiert Slot für Slot herein. Drücke Fill code, um die Kaskade zu sehen.
Status
status zeigt das Ergebnis der Codeprüfung. loading sperrt die Slots und markiert das Feld als beschäftigt, error markiert jeden Slot als ungültig, und success färbt die Kanten grün. Jeder wird angesagt. Mit animated läuft bei loading eine Welle, bei error wackelt es einmal, und bei success poppen die Zeichen.
Kontrolliert
Übergib value und onValueChange. Der Wert ist immer der gefilterte Code, nie länger als length.
Form
Mit einem name wird der Code mit dem Formular gesendet. autoSubmit sendet ab, sobald der letzte Slot gefüllt ist, sodass ein automatisch ausgefüllter Code Nutzer ohne weiteres Tippen anmeldet.
Mit Field
In einem <Field /> sind Label, Beschreibung und Fehler automatisch verknüpft. Gib etwas anderes als 000000 ein, um den Fehler zu sehen.
Ungültig
aria-invalid an der Root markiert jeden Slot. Verknüpfe die Meldung mit aria-describedby.
Buchstaben und Zahlen
validationType="alphanumeric" akzeptiert Wiederherstellungs- und Einladungscodes, und normalizeValue wandelt sie beim Tippen oder Einfügen in Großbuchstaben um.
Maskiert
mask verbirgt jedes Zeichen, für PINs. Schalte Autofill mit autoComplete="off" ab, wenn der Wert kein Einmalcode ist.
Eigenes Trennzeichen
Gruppiere die Slots beliebig und übergib dein eigenes Icon an <InputOTPSeparator />.
Deaktiviert
Ein deaktiviertes Feld lässt sich weder fokussieren noch bearbeiten.
Rechts nach links
Slots füllen sich von rechts, und die Pfeiltasten folgen dem, was du siehst. Gib Slots nach dem ersten ein übersetztes aria-label. Setze dir="ltr" am Feld, um einen Code auf einer Rechts-nach-links-Seite von links nach rechts zu halten.
| Taste | Aktion |
|---|---|
| Tab | Setzt den Fokus in das Feld, auf den ersten leeren Slot, und wieder hinaus. Nur ein Slot liegt in der Tab-Reihenfolge. |
| ←→ | Wechselt zum vorherigen oder nächsten Slot, in Rechts-nach-links-Layouts in visueller Reihenfolge. |
| Home↑ | Wechselt zum ersten Slot. |
| End↓ | Wechselt zum Slot nach dem letzten Zeichen. |
| Backspace | Löscht das Zeichen im Slot oder das davor, wenn der Slot leer ist. Spätere Zeichen rücken nach. |
| Delete | Löscht das Zeichen im Slot und behält den Fokus dort. |
| CtrlBackspace | Leert den ganzen Code. ⌘ Backspace unter macOS. |
| CtrlA | Wählt den ganzen Code aus (⌘ A unter macOS). Backspace oder Entf leert ihn dann und kehrt zum ersten Slot zurück, Tippen oder Einfügen ersetzt ihn, und Strg+C kopiert alles. Jede andere Taste oder ein Klick beendet die Auswahl. |
- Jeder Slot ist ein echtes Input. Der erste übernimmt seinen Namen von deinem
<label>oderaria-label; die anderen heißen „Character 2 of 6“ und so weiter. Übergibaria-labelan einem Slot, um ihn zu übersetzen. - Der erste Slot hat
autocomplete="one-time-code", sodass iOS und macOS Codes aus Nachrichten und Mail anbieten, Android SMS-Codes anbietet und Passwortmanager ihn füllen können. Ein ganzer Code, der in einem Slot landet, wird auf alle verteilt. Die animierte Kaskade läuft für jede Quelle, auch für Codes, die du über die WebOTP-API setzt. - Wann immer der Code leer wird, während ein Slot den Fokus hat, etwa nachdem ein falscher Code geleert wurde, wandert der Fokus zurück zum ersten Slot, sodass der nächste Versuch an der richtigen Stelle beginnt.
- Ist
statusgesetzt, sagt eine verborgene Live-Region neben dem Feld ihn an. Ändere den Wortlaut mitloadingLabel,successLabelunderrorLabel. - Mit
animatedwerden Zeichen auf einer für Screenreader verborgenen Ebene gezeichnet, während die Inputs den echten Wert behalten. Bei reduzierter Bewegung blenden Zeichen nur ein und aus, und die Statuswelle wird zu einem sanften Pulsieren.
Basiert auf dem Base UI OTP Field. Jede Base-UI-Prop wird durchgereicht.
| Prop | Typ | Standard |
|---|---|---|
lengthErforderlich. Die Anzahl der Slots; rendere dieselbe Anzahl von InputOTPSlot-Teilen. | number | – |
variant | "joined" | "separate" | "joined" |
size | "sm" | "default" | "lg" | "default" |
animatedAnimiert Zeichen beim Ein- und Ausblenden, lässt mehrstellige Eingaben kaskadieren und animiert den Status. | boolean | false |
statusDas Ergebnis der Codeprüfung. Loading macht die Slots schreibgeschützt. | "idle" | "loading" | "success" | "error" | – |
loadingLabel | string | "Verifying code" |
successLabel | string | "Code verified" |
errorLabel | string | "Code is incorrect" |
value | string | – |
defaultValue | string | – |
onValueChange | (value: string, details) => void | – |
onValueCompleteWird aufgerufen, wenn der letzte Slot gefüllt wird. | (value: string, details) => void | – |
onValueInvalidWird aufgerufen, wenn getippte oder eingefügte Zeichen abgelehnt werden. | (value: string, details) => void | – |
validationType | "numeric" | "alpha" | "alphanumeric" | "none" | "numeric" |
normalizeValueLäuft nach dem Filtern. Halte es idempotent. | (value: string) => string | – |
inputModeStandardmäßig aus validationType. | string | – |
autoComplete | string | "one-time-code" |
autoSubmit | boolean | false |
mask | boolean | false |
aria-invalidMarkiert jeden Slot als ungültig. | boolean | – |
name | string | – |
form | string | – |
idSitzt am ersten Slot, sodass das htmlFor eines Labels darauf zeigt. | string | – |
disabled | boolean | false |
readOnly | boolean | false |
required | boolean | false |
className | string | (state) => string | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Beschreibung |
|---|---|
data-slot="input-otp" | Das Root. |
data-variant="joined" | "separate" | Die aktuelle Variante. |
data-size | Die aktuelle Größe. |
data-status | Der Status, wenn einer gesetzt ist. |
data-animated | Vorhanden, wenn animated aktiv ist. |
data-shake | Vorhanden, während das Feld wackelt, nachdem der Status auf error gewechselt hat. |
data-complete | Vorhanden, wenn jeder Slot gefüllt ist. |
data-filled | Vorhanden, wenn ein Slot gefüllt ist. |
data-focused | Vorhanden, solange ein Slot den Fokus hat. |
data-disabled | Vorhanden, wenn deaktiviert. |
data-readonly | Vorhanden, wenn schreibgeschützt, auch während des Ladens. |
data-required | Vorhanden, wenn erforderlich. |
data-invalid / data-valid / data-touched / data-dirty | Feldzustand, innerhalb eines Field. |
data-slot="input-otp-status" | Die verborgene Live-Region, ein Geschwisterelement der Root. |
Ein einfaches Element, das eine Folge von Slots anordnet. In der Variante joined teilen sich seine Slots die Kanten.
| Prop | Typ | Standard |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Beschreibung |
|---|---|
data-slot="input-otp-group" | Die Gruppe in CSS ansprechen. |
Eine Box mit einem Input. className geht an die Box; jede andere Prop geht an das Input.
| Prop | Typ | Standard |
|---|---|---|
aria-labelWird am ersten Slot ignoriert, der das Label verwendet. | string | "Character N of M" |
classNameDer State enthält Index, Wert und filled des Slots sowie den Feldzustand. | string | (state) => string | – |
placeholder | string | – |
| Attribut | Beschreibung |
|---|---|
data-slot="input-otp-slot" | Die Box. |
data-filled | Vorhanden, wenn der Slot ein Zeichen hat. |
data-status | Der Status der Root, wenn nicht idle. |
--input-otp-index | Die Position des Slots, mit der die Statusbewegung gestaffelt wird. |
data-slot="input-otp-input" | Das Input darin, mit den Base-UI-Attributen data-filled, data-focused, data-complete und den Feld-Attributen. |
data-slot="input-otp-char" | Das gezeichnete Zeichen, wenn animated aktiv ist. |
Ein Trennzeichen mit einem Minus-Icon. Übergib Kinder, um ein anderes Icon zu verwenden.
| Prop | Typ | Standard |
|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" |
className | string | (state) => string | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribut | Beschreibung |
|---|---|
data-slot="input-otp-separator" | Das Trennzeichen in CSS ansprechen. |
Die Klassennamen hinter einem Slot und einer Gruppe (inputOTPGroupVariants). Rufe sie mit { variant, size } auf.
- MotionDie Easing-Kurven, Dauern und der Reduced-Motion-Check, mit denen jede Komponente animiert, plus Hooks für Größen-Morphs und gleitende Hervorhebungen.
- CalendarEin Datumsraster für Einzel-, Bereichs- und Mehrfachauswahl, mit gleitenden Monaten, Bereichsvorschau und Tagen in Touch-Größe.
- CheckboxEine Checkbox, deren Häkchen sich einzeichnet, mit unbestimmten übergeordneten Elementen, Gruppen und Labels, die ihren Hover teilen.
- ComboboxEin filterbares Select mit Chips, Gruppen und asynchronen Ergebnissen, in einem Popup, das sich beim Tippen anpasst.
- Date pickerEin Button, der einen Kalender in einem Popover öffnet, auf Smartphones als Bottom Sheet, für einzelne Daten und Zeiträume.
- FieldLabels, Beschreibungen und Fehler, mit ihrem Steuerelement verbunden, mit Validierungszuständen und Layouts für Formulare.
In Blocks verwendet
Blocks, die auf Input OTP aufbauen.
- ProfileDer Bereich „Profil“ in den Einstellungen eines KI-Produkts. Ein Foto kreisförmig zuschneiden, einen Benutzernamen wählen, der beim Tippen geprüft wird, eine neue E-Mail mit einem 6-stelligen Code bestätigen, Links hinzufügen, die die Website erkennen, und eine Live-Karte sehen, wie andere dich sehen.
- SecuritySitzungen und Sicherheit für ein KI-Produkt. Aktive Geräte mit Abmelden, bei dem Zeilen animiert verschwinden, eine Passwortänderung mit Live-Stärkeanzeige, Zwei-Faktor-Einrichtung mit echtem QR-Code, einer 6-stelligen Prüfung und herunterladbaren Wiederherstellungscodes, Passkeys über WebAuthn und Kontolöschung hinter einer getippten Bestätigung.