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-456 werden 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.

Gib den 6-stelligen Code ein, den du per SMS erhalten hast.
<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.

AttributBeschreibung
data-bs-otpInitialisiert die OTP-Eingabe am Container.
data-bs-lengthAnzahl der Felder. Standard: maxlength des Inputs.
data-bs-typenumeric (Standard), alphanumeric oder alpha.
data-bs-maskBei true wird jedes Zeichen als Punkt angezeigt.
data-bs-groupsArray mit Gruppengrößen (z. B. [3,3]) für Trenner.
data-bs-separatorZeichen 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.

NameTypStandardBeschreibung
lengthnumber, nullnullAnzahl der Felder; bei null aus maxlength gelesen.
typestring'numeric'Erlaubte Zeichen: numeric, alphanumeric, alpha. Setzt inputmode und pattern.
maskbooleanfalseZeigt statt des Zeichens einen Punkt (•).
groupsarray, nullnullGruppengrößen für Trenner, z. B. [3, 3].
separatorstring'·'Zeichen zwischen den Gruppen.

Methoden

MethodeBeschreibung
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

EventBeschreibung
complete.bs.otpInputWird ausgelöst, sobald alle Felder gefüllt sind. event.value enthält den Code.
input.bs.otpInputWird 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-label oder <label> und ergänze Kontext mit aria-describedby.
  • Die Komponente setzt autocomplete="one-time-code" und einen passenden inputmode, 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).