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 caractereInstalaçã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>
| Prop | Type | Default | Description |
|---|---|---|---|
maxLength | number | - | Número total de slots. Obrigatório. |
value | string | - | Valor controlado. |
onChange | (value: string) => void | - | Dispara a cada tecla digitada e paste. |
pattern | RegExp | string | - | Restringe os caracteres permitidos (ex. ^[0-9]+$ para apenas dígitos). |
containerClassName | string | - | Classes aplicadas à row wrapper, não ao input subjacente. |
className | string | - | 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>
| Prop | Type | Default | Description |
|---|---|---|---|
index | number | - | 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
<InputOTP>é a raiz controlada - dono dovalue,maxLength, e do input oculto subjacente.<InputOTPGroup>é um cluster visual. Você pode renderizar múltiplos porInputOTPe separá-los com<InputOTPSeparator />.<InputOTPSlot index={n} />é uma célula de caractere. Os slots leem seu estado doOTPInputContextcompartilhado 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.
'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-otprenderiza 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;
Backspacelimpa 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.