Input OTP
Slots de código de uso único que aceitam digitação, colagem e preenchimento automático de SMS, com uma animação opcional que faz os códigos entrarem em cascata e um status para a verificação.
Type or paste 123456 to pass. Anything else fails.
pnpm dlx shadcn@latest add https://hextaui.com/r/input-otp.jsonAdiciona o componente, os tokens de tema do HextaUI e quaisquer componentes do HextaUI dos quais ele depende.
Adicione os tokens de tema ao seu CSS global, se ainda não o fez.
Instale as dependências.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopie e cole o código a seguir no seu projeto.
components/ui/input-otp.tsx lib/motion.ts Atualize os caminhos de importação para corresponder à configuração do seu projeto.
Renderize um <InputOTPSlot /> por caractere e defina length com o mesmo número. Os slots encontram a própria posição sozinhos, então não há uma prop index para manter em sincronia.
Unido
A aparência padrão. Cada <InputOTPGroup /> une seus slots em uma única faixa com bordas compartilhadas.
Separado
variant="separate" dá a cada slot a própria caixa arredondada, com um espaço entre elas.
Tamanhos
sm, default e lg correspondem às alturas do input e do botão. Em telas sensíveis ao toque, todo tamanho cresce para pelo menos 44px com fonte de 16px.
Animado
animated vem desativado por padrão. Com ele, os caracteres digitados sobem, os apagados descem enquanto os demais deslizam, e um código inteiro vindo do preenchimento automático, de uma colagem ou do seu próprio estado entra em cascata, slot a slot. Pressione Fill code para ver a cascata.
Status
status mostra o resultado da verificação do código. loading trava os slots e marca o campo como ocupado, error marca todos os slots como inválidos e success deixa as bordas verdes. Cada um é anunciado. Com animated, loading executa uma onda, error balança uma vez e success faz os caracteres saltarem.
Controlado
Passe value e onValueChange. O valor é sempre o código filtrado, nunca maior que length.
Form
Com um name, o código é enviado com o formulário. autoSubmit envia assim que o último slot é preenchido, então um código preenchido automaticamente faz o login sem mais um toque.
Com Field
Dentro de um <Field />, o rótulo, a descrição e o erro são vinculados para você. Digite qualquer coisa diferente de 000000 para ver o erro.
Inválido
aria-invalid na raiz marca todos os slots. Vincule a mensagem com aria-describedby.
Letras e números
validationType="alphanumeric" aceita códigos de recuperação e de convite, e normalizeValue os converte em maiúsculas conforme são digitados ou colados.
Mascarado
mask oculta cada caractere, para PINs. Desative o preenchimento automático com autoComplete="off" quando o valor não for um código de uso único.
Separador personalizado
Agrupe os slots como quiser e passe seu próprio ícone a <InputOTPSeparator />.
Desabilitado
Um campo desativado não pode receber foco nem ser editado.
Da direita para a esquerda
Os slots são preenchidos pela direita e as teclas de seta seguem o que você vê. Dê aos slots depois do primeiro um aria-label traduzido. Defina dir="ltr" no campo para manter um código da esquerda para a direita em uma página da direita para a esquerda.
| Tecla | Ação |
|---|---|
| Tab | Move o foco para dentro do campo, até o primeiro slot vazio, e de volta para fora. Apenas um slot está na ordem de tabulação. |
| ←→ | Move para o slot anterior ou seguinte, em ordem visual em layouts da direita para a esquerda. |
| Home↑ | Move para o primeiro slot. |
| End↓ | Move para o slot depois do último caractere. |
| Backspace | Apaga o caractere do slot, ou o anterior quando o slot está vazio. Os caracteres seguintes recuam. |
| Delete | Apaga o caractere do slot e mantém o foco nele. |
| CtrlBackspace | Limpa o código inteiro. ⌘ Backspace no macOS. |
| CtrlA | Seleciona o código inteiro (⌘ A no macOS). Backspace ou Delete então o limpa e volta ao primeiro slot, digitar ou colar o substitui, e Ctrl C copia tudo. Qualquer outra tecla ou um clique encerra a seleção. |
- Cada slot é um input de verdade. O primeiro recebe seu nome do seu
<label>ou dearia-label; os demais se chamam "Character 2 of 6" e assim por diante. Passearia-labelem um slot para traduzi-lo. - O primeiro slot tem
autocomplete="one-time-code", então o iOS e o macOS oferecem códigos do Mensagens e do Mail, o Android oferece códigos de SMS e os gerenciadores de senhas podem preenchê-lo. Um código inteiro que cai em um só slot é distribuído por todos eles. A cascata animada roda para toda origem, inclusive códigos definidos pela API WebOTP. - Sempre que o código fica vazio enquanto um slot tem foco, como depois de um código errado ser limpo, o foco volta ao primeiro slot para que a próxima tentativa comece no lugar certo.
- Quando
statusestá definido, uma região live oculta ao lado do campo o anuncia. Altere as palavras comloadingLabel,successLabeleerrorLabel. - Com
animated, os caracteres são desenhados em uma camada oculta para leitores de tela enquanto os inputs mantêm o valor real. Com movimento reduzido, os caracteres apenas fazem fade e a onda de status vira um pulso suave.
Construído sobre o campo OTP do Base UI. Toda prop do Base UI é repassada.
| Prop | Tipo | Padrão |
|---|---|---|
lengthObrigatório. O número de slots; renderize o mesmo número de partes InputOTPSlot. | number | – |
variant | "joined" | "separate" | "joined" |
size | "sm" | "default" | "lg" | "default" |
animatedAnima a entrada e a saída dos caracteres, faz em cascata a entrada de vários caracteres e anima o status. | boolean | false |
statusO resultado da verificação do código. Loading deixa os slots como somente leitura. | "idle" | "loading" | "success" | "error" | – |
loadingLabel | string | "Verifying code" |
successLabel | string | "Code verified" |
errorLabel | string | "Code is incorrect" |
value | string | – |
defaultValue | string | – |
onValueChange | (value: string, details) => void | – |
onValueCompleteChamado quando o último slot é preenchido. | (value: string, details) => void | – |
onValueInvalidChamado quando caracteres digitados ou colados são rejeitados. | (value: string, details) => void | – |
validationType | "numeric" | "alpha" | "alphanumeric" | "none" | "numeric" |
normalizeValueExecuta após a filtragem. Mantenha-a idempotente. | (value: string) => string | – |
inputModeO padrão vem de validationType. | string | – |
autoComplete | string | "one-time-code" |
autoSubmit | boolean | false |
mask | boolean | false |
aria-invalidMarca todos os slots como inválidos. | boolean | – |
name | string | – |
form | string | – |
idVai no primeiro slot, para que o htmlFor de um rótulo aponte para ele. | string | – |
disabled | boolean | false |
readOnly | boolean | false |
required | boolean | false |
className | string | (state) => string | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descrição |
|---|---|
data-slot="input-otp" | A raiz. |
data-variant="joined" | "separate" | A variante atual. |
data-size | O tamanho atual. |
data-status | O status, quando um está definido. |
data-animated | Presente quando animated está ativado. |
data-shake | Presente enquanto o campo balança depois que o status vira error. |
data-complete | Presente quando todos os slots estão preenchidos. |
data-filled | Presente quando qualquer slot está preenchido. |
data-focused | Presente enquanto um slot tem foco. |
data-disabled | Presente quando desabilitado. |
data-readonly | Presente quando somente leitura, inclusive durante o carregamento. |
data-required | Presente quando obrigatório. |
data-invalid / data-valid / data-touched / data-dirty | Estado do campo, dentro de um Field. |
data-slot="input-otp-status" | A região live oculta, irmã da raiz. |
Um elemento simples que organiza uma sequência de slots. Na variant joined, os slots compartilham as bordas.
| Prop | Tipo | Padrão |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descrição |
|---|---|
data-slot="input-otp-group" | Selecione o grupo no CSS. |
Uma caixa que contém um input. className vai na caixa; todas as outras props vão no input.
| Prop | Tipo | Padrão |
|---|---|---|
aria-labelIgnorado no primeiro slot, que usa o rótulo. | string | "Character N of M" |
classNameO estado tem o índice do slot, o valor, filled e o estado do campo. | string | (state) => string | – |
placeholder | string | – |
| Atributo | Descrição |
|---|---|
data-slot="input-otp-slot" | A caixa. |
data-filled | Presente quando o slot tem um caractere. |
data-status | O status da raiz, quando não é idle. |
--input-otp-index | A posição do slot, usada para escalonar o movimento do status. |
data-slot="input-otp-input" | O input interno, com os atributos data-filled, data-focused, data-complete e de campo do Base UI. |
data-slot="input-otp-char" | O caractere desenhado quando animated. |
Um separador com um ícone de menos. Passe children para usar outro ícone.
| Prop | Tipo | Padrão |
|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" |
className | string | (state) => string | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descrição |
|---|---|
data-slot="input-otp-separator" | Seleciona o separador no CSS. |
Os nomes de classe por trás de um slot e de um grupo (inputOTPGroupVariants). Chame-os com { variant, size }.
- MotionAs curvas de easing, as durações e a verificação de movimento reduzido com que todo componente anima, além de hooks para transformações de tamanho e destaques deslizantes.
- CalendarUma grade de datas para seleção única, de intervalo e múltipla, com meses deslizantes, prévias de intervalo e dias com tamanho adequado ao toque.
- CheckboxUma caixa de seleção cujo check é desenhado na tela, com pais indeterminados, grupos e rótulos que compartilham seu hover.
- ComboboxUm select filtrável com chips, grupos e resultados assíncronos, em um popup que se redimensiona conforme você digita.
- Date pickerUm botão que abre um calendário em um popover, ou em um bottom sheet no celular, para datas únicas e intervalos.
- FieldRótulos, descrições e erros ligados ao seu controle, com estados de validação e layouts para formulários.
Usado em blocos
Blocos que se baseiam em Input OTP.
- ProfileA seção Perfil das configurações de um produto de IA. Recorte uma foto em um círculo, escolha um nome de usuário que é verificado enquanto você digita, confirme um novo e-mail com um código de 6 dígitos, adicione links que reconhecem o site e veja um card ao vivo de como os outros veem você.
- SecuritySessões e segurança para um produto de IA. Dispositivos ativos com encerramento de sessão que anima a saída das linhas, troca de senha com um medidor de força em tempo real, configuração de autenticação em duas etapas com um QR code real, uma verificação de 6 dígitos e códigos de recuperação para baixar, passkeys via WebAuthn e exclusão de conta protegida por uma confirmação digitada.