Por que o input de número é o pior tipo de input

Publicado em 22 de Dezembro

Leitura de 6 minutos

Esse é um artigo retirado em inglês do Stackoverflow

Você acha que um formulário web capturou seu número?

Se você usou input type="number", pode se surpreender ao descobrir que não.

Escrevo código há pelo menos 15 anos. Embora eu tenha usado muitas tecnologias e construído muita coisa ao longo dos anos, o que mais fiz foi front-end, ou seja, HTML, CSS e JavaScript. E de tudo o que construí no front-end, o que mais fiz foram formulários.

Não vou fingir ser o especialista definitivo em tudo relacionado a formulários. Mas posso dizer o seguinte: de todas as exigências difíceis, não convencionais e incomuns que recebi nesses 15 anos, a maioria girava em torno da construção de formulários. Cada uma apresentava um desafio que exigia algum tipo de solução fora do padrão. Aprendi muitas formas de superar esses desafios: o que você deve fazer e, mais importante, o que você não deve fazer.

De tudo o que aprendi sobre o que não fazer, um dos conselhos mais simples e valiosos que posso dar é este:

a menos que o caso de uso seja extremamente simples, evite usar o input de número.

Vi tantos formulários problemáticos que me senti obrigado a criar meu próprio construtor de formulários, capaz de lidar com pedidos mais complexos sem a necessidade de escrever código do zero toda vez. O Keenforms é um construtor de formulários drag-and-drop com um mecanismo de regras no-code. Ele facilita a criação de funcionalidades dinâmicas e condicionais sem escrever código do zero.

Recentemente recebi alguns feedbacks sobre o Keenforms, e a crítica mais comum foi o fato de ele não usar <input type="number" />. Temos um campo rotulado como número, mas quando você o adiciona ao formulário, ele é renderizado como <input type="text" />.

Observação: o Keenforms realmente usa o input de número internamente, mas apenas no dashboard e somente para os casos mais simples.

Argumentos a favor do input de número

Quem defende o uso do input de número tem preocupações legítimas, principalmente em relação à acessibilidade:

  • Possui botões nativos de incremento/decremento
  • Validação nativa para verificar se é um número
  • Em dispositivos móveis, exibe teclado numérico
  • Facilita o uso por leitores de tela

Também existem críticas válidas ao uso excessivo de JavaScript (culpado!). Eu entendo a aversão de algumas pessoas ao JavaScript. No entanto, todos os formulários complexos que construí exigiram uso intenso de JavaScript — é a única forma de fornecer feedback instantâneo e lógica condicional dinâmica. O Keenforms depende fortemente de JavaScript, especificamente React.

Mesmo assim, há muitos problemas com inputs de número quando se trata de lógica complexa e condicional — principalmente relacionados ao JavaScript — e por isso, nos últimos anos, decidi evitá-los.

Vale notar que não estou sozinho nesse posicionamento. O governo do Reino Unido publicou um artigo detalhando vários problemas relacionados ao input de número.

O curioso é que os problemas citados nesse artigo nem foram os principais motivos pelos quais decidi evitá-lo. Após receber feedbacks sobre o Keenforms, percebi que muitos programadores não fazem ideia dos problemas que o input de número causa.

A lista não é longa, mas os problemas são chocantes.

Os principais problemas do input de número

1. Valores inválidos retornam string vazia

Quando o input de número contém um valor inválido e você tenta recuperá-lo, o valor retornado é uma string vazia.

const numberInput = document.getElementById("id_here");
console.log(numberInput.value); // retorna string vazia se inválido

Isso acontece tanto ao acessar via event.target.value quanto diretamente pelo DOM.

Se você está construindo um formulário com validações condicionais ou cálculos, esse é um problema enorme. O input permite que o usuário digite um valor inválido, mas você não consegue recuperar esse valor para validá-lo corretamente.

Para idade ou quantidade simples isso pode não parecer grave, mas imagine um formulário de seguro de vida com regras como:

  • Quantidade de dependentes define quantos formulários aninhados serão exibidos

  • Percentual de benefício para cada dependente

    • Se houver apenas um dependente: campo oculto e valor automático de 100
    • Se houver mais de um: campo visível, valor mínimo de 0,01 e máximo menor que 100
  • Um campo oculto que soma os percentuais e valida se o total é exatamente 100

Todos esses requisitos exigem JavaScript. E eu não consigo fazer meu trabalho sem acessar esses valores, sejam eles válidos ou não.

Números válidos não são apenas dígitos

Esse é o outro lado do problema: o input de número permite valores que são tecnicamente válidos, mas que provavelmente você não quer.

Muitas vezes você usa input type="number" esperando um número inteiro, como idade ou quantidade. Porém, o input aceita notação científica, como 2.3e4, que representa 23.000. Alguns navegadores convertem automaticamente números grandes para esse formato.

Diferentes navegadores aceitam caracteres diferentes

Chrome e Microsoft Edge

Caracteres permitidos:

  • Números de 0 a 9
  • Ponto decimal
  • - (valores negativos)
  • + e e para notação científica

Esses navegadores impedem repetir caracteres inválidos, mas permitem colocá-los em qualquer posição, tornando o valor inválido e inacessível via JavaScript.

Firefox e Safari

Não há restrição alguma. Você pode digitar qualquer coisa.

Todos os navegadores exibem um popup nativo indicando valor inválido e bloqueiam o envio do formulário. Porém, essa validação visual costuma ser inconsistente com o UX da aplicação, algo que geralmente desagrada designers e product managers.

Limites de mínimo e máximo podem ser burlados

Definir min e max é útil, e os botões de incremento respeitam esses limites. Porém, é possível colar valores fora do intervalo:

<input type="number" min="1" max="10" />

Isso pode virar um problema em testes e planejamento de sprint, mesmo sendo comportamento padrão do input.

O que usar no lugar do input de número

Use o input de número apenas para valores matematicamente relevantes, como idade ou quantidade. Nunca para CEP, telefone, CPF, etc.

Se o campo:

  • Não tem validação condicional
  • Sempre está dentro de um intervalo fixo
  • Não afeta outros campos

Então usar type="number" não é um grande problema.

Caso contrário, abandone-o.

Alternativas

  • Para inteiros simples:

    <input type="text" inputmode="numeric" pattern="[0-9]*" />
    
  • Para casos avançados:

    <input type="text" />
    

E faça toda a validação via JavaScript.

Isso exige mais esforço e perde os botões de incremento, mas é um custo que precisei aceitar para casos complexos.

Acessibilidade ainda importa

Isso não significa sacrificar acessibilidade. Existem outras formas de atingir o mesmo resultado:

  • Forçar teclado numérico em inputs de texto
  • Usar rótulos claros
  • Mensagens de erro compatíveis com leitores de tela

Ferramentas como o WAVE Accessibility Tool ajudam bastante.

É impossível entregar funcionalidades complexas usando input type="number". É uma escolha entre simplicidade ou controle total.

E, na maioria dos casos, vale mais a pena abandonar o input de número.