KDS
Forms

InputOTP

Input segmentado para códigos de uso único (2FA, verificação SMS).

Overview

InputOTP é um input segmentado para códigos efêmeros — cada dígito num slot visualmente separado, mas comportamento de input único: paste de "123456" preenche tudo, autocomplete one-time-code funciona, foco salta entre slots.

Construído sobre input-otp. Use em 2FA, verificação por SMS, confirmação de e-mail, qualquer código curto e descartável. Para senhas/PINs persistentes, use Input com type="password".

Preview
6 dígitos com separador 3-3.

Anatomy

<InputOTP maxLength>
  ├─ <InputOTPGroup>
  │    └─ <InputOTPSlot index={n} />
  └─ <InputOTPSeparator /> (opcional, decorativo)
</InputOTP>

InputOTP sob o capô é um único <input type="text"> invisível que captura digitação, paste e autocomplete; os slots são puramente visuais e refletem o estado via context.

Usage

"use client";

import * as React from "react";
import {
  InputOTP,
  InputOTPGroup,
  InputOTPSlot
} from "@kalvner/kds/forms/input-otp";

export function VerifyForm() {
  const [code, setCode] = React.useState("");
  return (
    <InputOTP maxLength={6} value={code} onChange={setCode}>
      <InputOTPGroup>
        {[0, 1, 2, 3, 4, 5].map((i) => (
          <InputOTPSlot key={i} index={i} />
        ))}
      </InputOTPGroup>
    </InputOTP>
  );
}

Props

InputOTP (Root)

PropTipoDefaultDescrição
maxLengthnumberQuantidade total de slots.
valuestringControlado.
onChange(v: string) => voidCallback.
patternstring (regex)'^[0-9]+$' opcionalRestringe caracteres.
containerClassNamestringClasse no container externo.
disabledbooleanfalseBloqueia.

InputOTPSlot

PropTipoDefaultDescrição
indexnumberPosição (0..maxLength-1).

Subcomponents

  • InputOTPGroup — agrupa slots; um group por bloco visual.
  • InputOTPSlot — slot individual; mostra char + caret animado.
  • InputOTPSeparator — separador decorativo (<MinusIcon />); não afeta paste/autocomplete.

Variants

4 dígitos
PIN curto, sem separador.

States

EstadoComportamento
Slot ativoBorder ring, ring 3px, caret animado pulsando.
Slot preenchidoChar visível em texto.
aria-invalidBorder destrutiva, ring destrutivo no slot ativo.
disabledContainer com opacity 50%.

Composition

Padrão típico — formulário de verificação 2FA:

<form onSubmit={handleVerify}>
  <Label htmlFor="otp">Código de verificação</Label>
  <InputOTP id="otp" maxLength={6} value={code} onChange={setCode}>
    <InputOTPGroup>
      {[0, 1, 2].map((i) => <InputOTPSlot key={i} index={i} />)}
    </InputOTPGroup>
    <InputOTPSeparator />
    <InputOTPGroup>
      {[3, 4, 5].map((i) => <InputOTPSlot key={i} index={i} />)}
    </InputOTPGroup>
  </InputOTP>
  <Button type="submit" disabled={code.length !== 6}>Verificar</Button>
</form>

Auto-submeta quando o código completar (code.length === maxLength) em fluxos rápidos — economiza um clique.

When to use

  • 2FA (TOTP do authenticator).
  • Verificação de e-mail por código.
  • Verificação por SMS.
  • PIN curto efêmero (recuperação de conta).

When not to use

  • Senhas / PINs persistentes — use Input type="password".
  • Códigos longos (>8 dígitos) — vira sopa visual; use Input normal.
  • Qualquer dado que precisa ser editado depois — InputOTP é digitação contínua.

Best practices

  • Bloco 3-3 (com InputOTPSeparator) para 6 dígitos é mais legível que 6 contínuos.
  • Auto-submita quando completar — usuário não precisa apertar Enter num código.
  • Use inputMode="numeric" (passe via prop) para teclado numérico no mobile.
  • Aria-label no Root descreva ("Código de verificação"); slots individuais não precisam.

Accessibility

ConcernComportamento
AutocompleteSuporta one-time-code automático no iOS Safari.
Paste"Colar" preenche todos os slots de uma vez.
KeyboardBackspace volta ao slot anterior; setas navegam.
MobileUse inputMode="numeric" para teclado numérico.
CaretSlot ativo mostra caret animado (visual feedback além do ring).
Live regionPara feedback de erro ("Código inválido"), use Alert ou Toast.
  • Input — input de texto regular.
  • Form — wrapper RHF + zod para validação.
  • Alert — feedback de erro de verificação.

On this page