
⚙️ Como restringir a entrada de caracteres indesejados em INPUT com JavaScript
Formulário de registo, campo de telefone, pesquisa no catálogo: o utilizador clica num INPUT e escreve o que quer. Letras onde se esperam dígitos. Caracteres especiais num número de encomenda. Emoji num campo de email. O resultado: lixo na base de dados, consultas quebradas, validação no backend a falhar com um erro.
O problema resolve-se no frontend em 15 linhas de código. Sem plugins, sem bibliotecas, apenas JavaScript simples ou um par de atributos HTML. Abaixo estão três abordagens funcionais: do rápido HTML5 à filtragem detalhada no keydown, com exemplos prontos para cenários comuns.
💡 Resumo rápido:
- Analisamos quando os atributos HTML
pattern,inputmodeetypesão suficientes e quando é necessário JavaScript - Escrevemos um filtro "apenas dígitos" em jQuery e JS puro, ambas as versões com explicação linha a linha
- Adicionamos proteção contra colagem via Ctrl+V e menu de contexto
- Construímos uma função modelo universal para quaisquer restrições: letras, caracteres latinos, máscaras personalizadas
HTML5: o que se pode fazer sem uma única linha de JavaScript
A forma mais simples e fiável de restringir a entrada é dizer ao navegador exatamente o que se espera num campo. Os navegadores modernos compreendem três atributos chave que cobrem as tarefas mais comuns.
type, o filtro principal. type="number" permite apenas dígitos, menos e separador decimal. type="tel" em dispositivos móveis mostra um teclado numérico. type="email" verifica a existência de @ no envio do formulário. type="url" exige um protocolo. Isto não bloqueia totalmente a entrada, mas fornece o teclado no ecrã correto e validação básica no envio.
pattern, uma expressão regular no campo. O atributo aceita uma regex e valida o valor no envio do formulário:
1 <input type="text" pattern="[0-9]{6}" placeholder="Six digits" title="Exactly 6 digits">
O navegador bloqueia o envio se o valor não corresponder ao padrão. A desvantagem: o pattern não impede a introdução de caracteres não permitidos; apenas valida o resultado. O utilizador pode escrever "abc" e só verá o erro ao tentar enviar o formulário.
inputmode, o teclado correto no telemóvel. inputmode="numeric" abre um teclado numérico, mas não proíbe a introdução de letras. inputmode="decimal" adiciona um separador. Útil em combinação com um filtro JavaScript: o teclado já está correto e o JS trata do resto.
O que escolher. Se precisar de impedir realmente a introdução de caracteres não permitidos em tempo real, os atributos HTML não são suficientes. Passemos ao JavaScript.
JavaScript: bloquear teclas via keydown
A abordagem keydown captura cada tecla premida antes de o caractere aparecer no campo. Se a tecla não estiver na lista de permissões, event.preventDefault() suprime-a.
Opção 1: jQuery, apenas dígitos
O código é anexado a um INPUT por id, permite dígitos e teclas de serviço (retrocesso, setas, Tab) e bloqueia tudo o resto:
1 $(document).ready(function() { 2 $("#phone_input").keydown(function(event) { 3 // Service keys — let them through 4 if (event.keyCode === 46 || event.keyCode === 8 || 5 event.keyCode === 9 || event.keyCode === 27 || 6 (event.keyCode === 65 && event.ctrlKey === true) || 7 (event.keyCode >= 35 && event.keyCode <= 39)) { 8 return; 9 } 10 // Block everything except digits (main block and numpad) 11 if ((event.keyCode < 48 || event.keyCode > 57) && 12 (event.keyCode < 96 || event.keyCode > 105)) { 13 event.preventDefault(); 14 } 15 }); 16 });
Eis o que acontece linha a linha: keyCode 46 (Delete), 8 (Backspace), 9 (Tab), 27 (Escape), 65 + Ctrl (selecionar tudo), 35..39 (Home, End, setas). Depois vêm os dígitos do bloco principal 48..57 (0..9) e do teclado numérico 96..105. Tudo o que não se enquadre nestes intervalos recebe preventDefault.
Tabela completa de key codes no Cambia Research.
Opção 2: JavaScript puro, apenas dígitos
O mesmo sem jQuery, usando onkeypress. Esta versão é mais compacta e não carrega uma biblioteca:
1 document.getElementById("phone_input").onkeypress = function(event) { 2 event = event || window.event; 3 if (event.charCode && (event.charCode < 48 || event.charCode > 57)) { 4 return false; 5 } 6 };
charCode verifica se o evento tem um caractere imprimível; as teclas de serviço (setas, retrocesso) passam automaticamente, pois o seu charCode é igual a 0. Dígitos: 48..57, tudo o resto devolve false.
Importante: keyCode é considerado obsoleto. Em código moderno, é melhor usar event.key, que devolve uma string com o nome da tecla e não depende da disposição do teclado:
1 element.addEventListener("keydown", function(event) { 2 // Allow digits, Backspace, Delete, arrows, Tab 3 const allowedKeys = [ 4 "Backspace", "Delete", "Tab", "Escape", 5 "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", 6 "Home", "End" 7 ]; 8 if (allowedKeys.includes(event.key)) return; 9 // Ctrl+A / Ctrl+C / Ctrl+V 10 if (event.ctrlKey) return; 11 // Only digits 12 if (!/^[0-9]$/.test(event.key)) { 13 event.preventDefault(); 14 } 15 });
A abordagem event.key lê-se de forma mais clara e não exige a memorização de códigos numéricos. Mas para suporte a navegadores mais antigos, a versão com keyCode acima ainda funciona.
Bloquear colagem: capturar Ctrl+V e menu de contexto
O keydown captura as teclas premidas, mas o utilizador pode colar texto via Ctrl+V ou clique direito → "Colar". Copiou "abc123" para um campo só de dígitos e metade passou.
A solução é o evento input. Ele dispara após QUALQUER alteração no valor do campo: introdução manual, colagem, autopreenchimento, arrastar e largar texto. Filtramos o valor final com uma expressão regular:
1 document.getElementById("digits_only").addEventListener("input", function(event) { 2 this.value = this.value.replace(/[^0-9]/g, ""); 3 });
É tudo. Uma linha e nem um único não-dígito passará pelo campo, independentemente de como lá chegou. Para letras: replace(/[^a-zA-Zа-яА-ЯёЁ]/g, ""). Para caracteres latinos: replace(/[^a-zA-Z]/g, "").
Abordagem combinada (o meio-termo ideal). O keydown fornece feedback instantâneo (a tecla "não pressiona"), enquanto o input protege contra a colagem. Use ambos os manipuladores:
1 const field = document.getElementById("digits_only"); 2 3 field.addEventListener("keydown", function(event) { 4 const allowed = ["Backspace", "Delete", "Tab", "Escape", 5 "ArrowLeft", "ArrowRight", "Home", "End"]; 6 if (allowed.includes(event.key)) return; 7 if (event.ctrlKey) return; 8 if (!/^[0-9]$/.test(event.key)) event.preventDefault(); 9 }); 10 11 field.addEventListener("input", function() { 12 this.value = this.value.replace(/[^0-9]/g, ""); 13 });
O primeiro manipulador corta instantaneamente as teclas não permitidas. O segundo limpa os resíduos após colagem e autopreenchimento.
Modelo pronto para quaisquer restrições
Vamos construir uma função que recebe um INPUT e uma expressão regular de caracteres permitidos. Funciona para números de telefone, códigos postais, logins, pesquisa de SKU:
1 function restrictInput(element, allowedPattern) { 2 element.addEventListener("keydown", function(event) { 3 const serviceKeys = [ 4 "Backspace", "Delete", "Tab", "Escape", 5 "ArrowLeft", "ArrowRight", "Home", "End" 6 ]; 7 if (serviceKeys.includes(event.key)) return; 8 if (event.ctrlKey && ["a", "c", "v", "x", "z"].includes(event.key.toLowerCase())) return; 9 if (!allowedPattern.test(event.key)) event.preventDefault(); 10 }); 11 12 element.addEventListener("input", function() { 13 // Build a global pattern from the provided one and clean 14 const globalPattern = new RegExp( 15 allowedPattern.source.replace("^", "").replace("$", ""), 16 "g" 17 ); 18 // Remove everything that does NOT match the pattern 19 const inverted = new RegExp( 20 "[^" + allowedPattern.source.slice(1, -1) + "]", "g" 21 ); 22 this.value = this.value.replace(inverted, ""); 23 }); 24 }
Utilização:
1 // Digits only 2 restrictInput(document.getElementById("phone"), /^[0-9]$/); 3 // Latin letters only without spaces 4 restrictInput(document.getElementById("login"), /^[a-zA-Z]$/); 5 // Letters and digits 6 restrictInput(document.getElementById("postal"), /^[a-zA-Z0-9]$/);
A função não depende de jQuery, funciona em todos os navegadores modernos e cobre três cenários: introdução manual (keydown), colagem (input), autopreenchimento (input).
Nota: o keydown não dispara em teclados virtuais de alguns dispositivos móveis; aí o input continua a ser a única salvaguarda. É por isso que dois manipuladores em conjunto não são redundância, mas sim necessidade.
O vídeo acima é uma análise de validação de formulários em JavaScript puro do Web Dev Simplified. Abrange a API de Validação de Restrições integrada, mensagens de erro personalizadas e estilização de campos inválidos, um ótimo complemento para as abordagens aqui descritas.
⁉️🤔 Perguntas frequentes
Porque não usar apenas type="number"?
O
type="number"permite introduzireeE(expoente), mais, menos e ponto. Todos estes são caracteres válidos para números de vírgula flutuante e notação exponencial. Para um campo de telefone ou código postal, são desnecessários. Além disso, os navegadores lidam com entradas não numéricas de forma diferente: alguns deixam-nas passar silenciosamente, outros mostram um erro apenas no envio.
É possível bloquear completamente a colagem via Ctrl+V?
Bloquear totalmente a colagem é uma má prática. Quebra a experiência do utilizador e não protege contra outros métodos de colagem (menu de contexto, arrastar e largar). A abordagem correta: permitir a colagem, mas limpar imediatamente o resultado através de um manipulador
input, como mostrado na secção acima.
E quanto ao autopreenchimento do navegador?
O autopreenchimento dispara antes do
keydowne doinput; o navegador insere o valor diretamente. O manipuladorinputtambém captura este caso: o valor aparece no campo e depois é filtrado imediatamente. Se o autopreenchimento estiver a interferir (inserindo letras num campo de telefone), adicione o atributoautocomplete="off"ao INPUT.
Isto funciona em dispositivos móveis?
Sim, mas com uma ressalva: os teclados virtuais nem sempre geram
keydowncomkeyCodeekeyesperados. O manipuladorinputfunciona de forma fiável em todo o lado. No telemóvel, definainputmode="numeric"ouinputmode="decimal"no INPUT; o utilizador receberá o teclado correto mesmo que o filtrokeydownnão dispare.
Como proibir espaços?
Adicione o espaço à classe de caracteres não permitidos:
replace(/[^0-9a-zA-Z]/g, "")remove tudo exceto dígitos e letras latinas, incluindo espaços. Ou explicitamente:this.value = this.value.replace(/\s/g, "")removerá todos os espaços, tabulações e quebras de linha.
Que abordagem escolher para a sua tarefa

Se o formulário for simples e alguns caracteres errados não causarem danos críticos, use HTML5: type, pattern e inputmode cobrirão os cenários básicos sem uma única linha de JS. Rápido, nativo, sem dependências.
Se o controlo em tempo real e a reação instantânea a cada tecla forem importantes, use a combinação keydown + input. O primeiro bloqueia as teclas, o segundo limpa as consequências da colagem. A função modelo universal da secção acima adapta-se a qualquer campo num minuto.
A regra principal: não bloqueie totalmente a colagem. Irrita os utilizadores e não oferece proteção real. Limpe o resultado após a colagem em vez de a proibir.



