OTP-Eingabe
Neu in Bootstrap v6.0.0
Einmalpasswörter, PINs und Bestätigungscodes erfassen – mit einem einzigen, barrierefreien Eingabefeld, das optisch als einzelne Ziffernfelder dargestellt wird.
OTP-Felder (One-Time Password) kennt man aus der Zwei-Faktor-Authentifizierung. Bootstrap 6 setzt dabei auf ein echtes Textfeld statt auf ein Feld pro Ziffer. Screenreader, Passwortmanager und SMS-Autofill behandeln es dadurch wie jedes andere Eingabefeld.
- Ein Feld: Hilfstechnologien kündigen nur ein Feld an, nicht eines pro Ziffer.
- Autofill:
autocomplete="one-time-code"wird unterstützt. - Einfügen: Auch formatierte Codes wie
123-456werden bereinigt übernommen. - Gezielt bearbeiten: Ein Klick auf ein Feld springt dorthin, die Eingabe überschreibt die Ziffer.
- Tastatur: Pfeiltasten, Backspace, Entf und Markieren funktionieren wie gewohnt.
- Maskierung und Zeichentypen: Wert verbergen, nur Ziffern, alphanumerisch oder nur Buchstaben.
Quelle: Bootstrap-Dokumentation (englisch), übersetzt und bearbeitet. Doku lizenziert unter CC BY 3.0.
Funktionsweise
Ein einzelnes <input> kommt in einen Container mit .otp, das Attribut data-bs-otp aktiviert das JavaScript. Die Anzahl der Felder ergibt sich aus maxlength. Das echte Feld liegt unsichtbar darüber, für jedes Zeichen wird ein .otp-slot gezeichnet. Vergib einen zugänglichen Namen per aria-label oder <label>.
<div class="otp" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Bestätigungscode">
</div>Verbundene Felder
Mit .otp-connected verschmelzen die Ziffernfelder zu einem zusammenhängenden Feld mit gemeinsamen Rändern.
<div class="otp otp-connected" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Bestätigungscode">
</div>Vierstellige PIN
Die Anzahl der Felder steuerst du über maxlength – für eine PIN reichen vier.
<div class="otp otp-connected" data-bs-otp>
<input type="text" class="otp-input" maxlength="4" aria-label="PIN">
</div>Mit Trenner
Über data-bs-groups mit einem Array von Gruppengrößen teilst du die Felder in Gruppen auf, z. B. für Codes wie „123-456“. Der Trenner ist rein dekorativ und wird nie Teil des Werts.
<div class="otp" data-bs-otp data-bs-groups="[3,3]">
<input type="text" class="otp-input" maxlength="6" aria-label="Bestätigungscode">
</div>Größen
Mit .otp-sm oder .otp-lg am Container änderst du die Feldgröße.
<div class="otp otp-sm mb-3" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Kleiner Bestätigungscode">
</div>
<div class="otp otp-lg" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Großer Bestätigungscode">
</div>Alphanumerisch und Maskierung
Standardmäßig sind nur Ziffern erlaubt. Mit data-bs-type="alphanumeric" oder "alpha" werden Buchstaben zugelassen. data-bs-mask="true" verbirgt den Wert, das Feld bleibt aber ein normales Textfeld – Ziffernblock und Autofill funktionieren weiterhin.
<div class="otp otp-connected mb-3" data-bs-otp data-bs-type="alphanumeric">
<input type="text" class="otp-input" maxlength="6" aria-label="Alphanumerischer Code">
</div>
<div class="otp otp-connected" data-bs-otp data-bs-mask="true">
<input type="text" class="otp-input" maxlength="6" aria-label="Maskierter Code">
</div>Deaktiviert
Das Attribut disabled am Input verhindert jede Eingabe.
<div class="otp otp-connected" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" aria-label="Bestätigungscode" disabled>
</div>Validierung
Mit .is-valid bzw. .is-invalid am Container zeigst du den Validierungsstatus an.
<div class="otp otp-connected is-valid mb-3" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" value="123456" aria-label="Bestätigungscode">
</div>
<div class="otp otp-connected is-invalid" data-bs-otp>
<input type="text" class="otp-input" maxlength="6" value="123" aria-label="Bestätigungscode">
</div>Mit Formular-Label
Verknüpfe ein <label> mit dem Input und ergänze einen Hilfetext über aria-describedby.
<div class="vstack gap-2">
<label class="form-label" for="otpCode">Bestätigungscode</label>
<div class="otp" data-bs-otp>
<input type="text" class="otp-input" id="otpCode" maxlength="6" aria-describedby="otpHelp">
</div>
<div id="otpHelp" class="form-text">Gib den 6-stelligen Code ein, den du per SMS erhalten hast.</div>
</div>Verwendung
Per Data-Attribute
data-bs-otp an einem Container mit genau einem <input> initialisiert die Komponente automatisch.
| Attribut | Beschreibung |
|---|---|
data-bs-otp | Initialisiert die OTP-Eingabe am Container. |
data-bs-length | Anzahl der Felder. Standard: maxlength des Inputs. |
data-bs-type | numeric (Standard), alphanumeric oder alpha. |
data-bs-mask | Bei true wird jedes Zeichen als Punkt angezeigt. |
data-bs-groups | Array mit Gruppengrößen (z. B. [3,3]) für Trenner. |
data-bs-separator | Zeichen für den Trenner zwischen den Gruppen. |
Per JavaScript
const otpElement = document.querySelector('.otp')
const otpInput = new bootstrap.OtpInput(otpElement)Optionen
Optionen lassen sich per Data-Attribut oder JavaScript übergeben.
| Name | Typ | Standard | Beschreibung |
|---|---|---|---|
length | number, null | null | Anzahl der Felder; bei null aus maxlength gelesen. |
type | string | 'numeric' | Erlaubte Zeichen: numeric, alphanumeric, alpha. Setzt inputmode und pattern. |
mask | boolean | false | Zeigt statt des Zeichens einen Punkt (•). |
groups | array, null | null | Gruppengrößen für Trenner, z. B. [3, 3]. |
separator | string | '·' | Zeichen zwischen den Gruppen. |
Methoden
| Methode | Beschreibung |
|---|---|
getValue() | Liefert den kompletten Code als String. |
setValue(value) | Setzt den Wert, bereinigt nach dem eingestellten Typ. |
clear() | Leert das Feld und setzt den Fokus. |
focus() | Fokussiert das Feld, Cursor hinter dem letzten Zeichen. |
dispose() | Entfernt die Instanz und die erzeugten Felder. |
const otpElement = document.querySelector('.otp')
const otpInput = bootstrap.OtpInput.getOrCreateInstance(otpElement)
console.log(otpInput.getValue())
otpInput.setValue('654321')
otpInput.clear()Events
| Event | Beschreibung |
|---|---|
complete.bs.otpInput | Wird ausgelöst, sobald alle Felder gefüllt sind. event.value enthält den Code. |
input.bs.otpInput | Wird bei jeder Änderung ausgelöst. event.value enthält den aktuellen Wert. |
const otpElement = document.querySelector('.otp')
otpElement.addEventListener('complete.bs.otpInput', event => {
console.log('Code vollständig:', event.value)
})
otpElement.addEventListener('input.bs.otpInput', event => {
console.log('Aktueller Wert:', event.value)
})Barrierefreiheit
Da die Komponente auf einem einzigen Textfeld basiert, gibt es genau einen zugänglichen Namen, eine Rolle und einen Wert. Die sichtbaren Ziffernfelder sind rein dekorativ und mit aria-hidden versehen – aria-label pro Ziffer ist nicht nötig.
- Gib dem Feld einen Namen per
aria-labeloder<label>und ergänze Kontext mitaria-describedby. - Die Komponente setzt
autocomplete="one-time-code"und einen passendeninputmode, damit Autofill greift und mobil die richtige Tastatur erscheint (WCAG 1.3.5). - Kopieren, Einfügen und Autofill werden nie blockiert (WCAG 3.3.8).
- Codes sollten großzügig lange gültig sein (WCAG 2.2.1), und ein bereits eingegebener Code sollte im selben Ablauf nicht erneut abgefragt werden (WCAG 3.3.7).