Skip to content

Tudo para WordPress, desenvolvimento web — e não só

⚙️ Como restringir a entrada de caracteres indesejados em INPUT com JavaScript

⚙️ 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, inputmode e type sã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 &lt; 48 || event.keyCode &gt; 57) &&
12 (event.keyCode &lt; 96 || event.keyCode &gt; 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:

1document.getElementById("phone_input").onkeypress = function(event) {
2 event = event || window.event;
3 if (event.charCode && (event.charCode &lt; 48 || event.charCode &gt; 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:

1element.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:

1document.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:

1const field = document.getElementById("digits_only");
2
3field.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
11field.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:

1function 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
2restrictInput(document.getElementById("phone"), /^[0-9]$/);
3// Latin letters only without spaces
4restrictInput(document.getElementById("login"), /^[a-zA-Z]$/);
5// Letters and digits
6restrictInput(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 introduzir e e E (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 keydown e do input; o navegador insere o valor diretamente. O manipulador input també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 atributo autocomplete="off" ao INPUT.

Isto funciona em dispositivos móveis?

Sim, mas com uma ressalva: os teclados virtuais nem sempre geram keydown com keyCode e key esperados. O manipulador input funciona de forma fiável em todo o lado. No telemóvel, defina inputmode="numeric" ou inputmode="decimal" no INPUT; o utilizador receberá o teclado correto mesmo que o filtro keydown nã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

Programador numa secretária com código no ecrã

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.