Skip to main content
Gremorie

Input OTP

Input de one-time-password segmentado construído sobre a biblioteca `input-otp`, com paste-to-fill, autocomplete e gerenciamento de focus entre slots.

Visão geral

InputOTP renderiza uma row de slots de caractere único que se comportam como um único <input> subjacente. Construído sobre o input-otp, ele cuida do movimento de caret entre slots, do paste-to-fill, e do autocomplete="one-time-code" do browser para que códigos de SMS / e-mail se auto-preencham em plataformas suportadas.

Use para 2FA, verificação de e-mail, confirmação por SMS - qualquer código efêmero que o usuário digita ou cola. Não o use para senhas ou PINs persistentes; esses precisam de um Input normal com type="password".

Preview

'use client';import { InputOTP, InputOTPGroup, InputOTPSlot } from '@gremorie/rx-forms';export function InputOTPPreview() {  return (    <InputOTP maxLength={6}>      <InputOTPGroup>        <InputOTPSlot index={0} />        <InputOTPSlot index={1} />        <InputOTPSlot index={2} />        <InputOTPSlot index={3} />        <InputOTPSlot index={4} />        <InputOTPSlot index={5} />      </InputOTPGroup>    </InputOTP>  );}

Anatomia

InputOTP                       OTPInput oculto dono do value + maxLength
├─ InputOTPGroup               cluster visual de slots contíguos
│  └─ InputOTPSlot             uma célula de caractere (lê seu char pelo index)
├─ InputOTPSeparator           um divisor MinusIcon entre grupos
└─ InputOTPGroup               outro cluster (códigos divididos 3 + 3)
   └─ InputOTPSlot             uma célula de caractere

Instalação

bash npx gremorie@latest add rx-input-otp
bash pnpm dlx gremorie@latest add rx-input-otp
bash yarn dlx gremorie@latest add rx-input-otp
bash bunx --bun gremorie@latest add rx-input-otp

Uso

import {
  InputOTP,
  InputOTPGroup,
  InputOTPSlot,
} from "@gremorie/rx-forms";

export function Example() {
  return (
    <InputOTP maxLength={6}>
      <InputOTPGroup>
        <InputOTPSlot index={0} />
        <InputOTPSlot index={1} />
        <InputOTPSlot index={2} />
        <InputOTPSlot index={3} />
        <InputOTPSlot index={4} />
        <InputOTPSlot index={5} />
      </InputOTPGroup>
    </InputOTP>
  );
}

A edição Angular deste componente hoje é entregue a partir do código-fonte (veja o workbench para o comparativo lado a lado); a entrada de registry vem em seguida.

API

<InputOTP>

PropTypeDefaultDescription
maxLengthnumber-Número total de slots. Obrigatório.
valuestring-Valor controlado.
onChange(value: string) => void-Dispara a cada tecla digitada e paste.
patternRegExp | string-Restringe os caracteres permitidos (ex. ^[0-9]+$ para apenas dígitos).
containerClassNamestring-Classes aplicadas à row wrapper, não ao input subjacente.
classNamestring-Classes aplicadas ao input subjacente (mantido visualmente oculto).

Estende todos os React.ComponentProps<typeof OTPInput> do input-otp. Renderiza com autocomplete="one-time-code" por padrão para que o browser ofereça o autofill de códigos SMS em dispositivos suportados.

<InputOTPGroup>

Cluster visual de InputOTPSlots. Adiciona flex items-center e permite dividir códigos em pedaços (ex. 3 + 3) renderizando múltiplos grupos separados por <InputOTPSeparator />.

Estende todos os React.ComponentProps<"div">.

<InputOTPSlot>

PropTypeDefaultDescription
indexnumber-Posição no valor subjacente (base 0). Obrigatório.

Lê o char ativo, o estado de focus, e a posição do caret falso do OTPInputContext e renderiza o visual correspondente.

<InputOTPSeparator>

<div role="separator"> decorativo renderizando um ícone de menos. Use entre grupos.

Composição

  1. <InputOTP> é a raiz controlada - dono do value, maxLength, e do input oculto subjacente.
  2. <InputOTPGroup> é um cluster visual. Você pode renderizar múltiplos por InputOTP e separá-los com <InputOTPSeparator />.
  3. <InputOTPSlot index={n} /> é uma célula de caractere. Os slots leem seu estado do OTPInputContext compartilhado com base em seu index.

Variações

Código de seis dígitos (grupo único)

O padrão mais comum para 2FA. maxLength={6} e seis slots dentro de um grupo.

<InputOTP maxLength={6}>
  <InputOTPGroup>
    {Array.from({ length: 6 }).map((_, i) => (
      <InputOTPSlot key={i} index={i} />
    ))}
  </InputOTPGroup>
</InputOTP>

PIN de quatro dígitos

Código PIN curto para confirmações. Reduza maxLength e a contagem de slots juntos.

<InputOTP maxLength={4}>
  <InputOTPGroup>
    <InputOTPSlot index={0} />
    <InputOTPSlot index={1} />
    <InputOTPSlot index={2} />
    <InputOTPSlot index={3} />
  </InputOTPGroup>
</InputOTP>

Agrupado 3 + 3 com separador

Divida um código de seis dígitos com um separador para legibilidade (espelha como os códigos são geralmente apresentados em e-mails: "123 456").

'use client';import {  InputOTP,  InputOTPGroup,  InputOTPSeparator,  InputOTPSlot,} from '@gremorie/rx-forms';export function InputOTPSeparatorPreview() {  return (    <InputOTP maxLength={6}>      <InputOTPGroup>        <InputOTPSlot index={0} />        <InputOTPSlot index={1} />        <InputOTPSlot index={2} />      </InputOTPGroup>      <InputOTPSeparator />      <InputOTPGroup>        <InputOTPSlot index={3} />        <InputOTPSlot index={4} />        <InputOTPSlot index={5} />      </InputOTPGroup>    </InputOTP>  );}

Pattern apenas numérico

Restrinja a entrada a dígitos via a prop pattern. Impede que os usuários digitem letras de qualquer forma.

'use client';import { InputOTP, InputOTPGroup, InputOTPSlot } from '@gremorie/rx-forms';// Restrict every slot to digits only. `pattern` is the regex string the// underlying input-otp library validates each keystroke against.const DIGITS_ONLY = '^\\d*$';export function InputOTPPatternPreview() {  return (    <InputOTP maxLength={6} pattern={DIGITS_ONLY}>      <InputOTPGroup>        <InputOTPSlot index={0} />        <InputOTPSlot index={1} />        <InputOTPSlot index={2} />        <InputOTPSlot index={3} />        <InputOTPSlot index={4} />        <InputOTPSlot index={5} />      </InputOTPGroup>    </InputOTP>  );}

Disabled

disabled na raiz esmaece cada slot e remove o campo da ordem de tabulação. O valor atual permanece legível.

1
2
3
4
5
6
'use client';import { InputOTP, InputOTPGroup, InputOTPSlot } from '@gremorie/rx-forms';export function InputOTPDisabledPreview() {  return (    <InputOTP maxLength={6} disabled defaultValue="123456">      <InputOTPGroup>        <InputOTPSlot index={0} />        <InputOTPSlot index={1} />        <InputOTPSlot index={2} />        <InputOTPSlot index={3} />        <InputOTPSlot index={4} />        <InputOTPSlot index={5} />      </InputOTPGroup>    </InputOTP>  );}

Acessibilidade

  • Um único input acessível: nos bastidores, o input-otp renderiza um elemento <input> que é dono do value, type, name, e da associação de label. Leitores de tela veem um campo, não seis.
  • Autocomplete: autocomplete="one-time-code" deixa iOS, Android e browsers modernos oferecerem o auto-fill de SMS.
  • Navegação por teclado: digitar move o caret para frente; Backspace limpa e volta; as setas navegam entre os slots; a seleção-para-paste espalha os caracteres pelos slots.
  • Paste-to-fill: colar um código completo em qualquer slot distribui os caracteres por todos os slots em ordem.
  • Slot ativo: o slot focado renderiza um caret piscante (animate-caret-blink) e um focus ring, para que os usuários sempre vejam onde a próxima tecla vai cair.
  • Estado invalid: aria-invalid="true" na raiz troca a borda de cada slot para o token destructive.

Relacionados

  • Input - o campo de texto de linha única canônico
  • Form - conecte o OTP ao react-hook-form para fluxos de verificação
  • Button - o típico trigger "Verify" embaixo do OTP

On this page