Pular para o conteúdo
ValidadorCNPJ Gerar CNPJ

Entrada de dados

Máscara de CNPJ com letras

Como aceitar 12.ABC.345/01DE-35 no seu formulário: máscara em JavaScript puro, nas principais bibliotecas, em Angular, React, Vue e Delphi.

A regra da máscara

Estrutura da máscara de CNPJ alfanumérico
PosiçõesAceitaSímbolo típico de máscara
1 a 12letra ou númeroA, C ou S, conforme a biblioteca
13 e 14apenas número9 ou 0
separadores. . / - nas mesmas posições de sempre

JavaScript puro (sem biblioteca)

Trinta linhas resolvem o caso completo: normaliza para maiúsculas, filtra caracteres inválidos, bloqueia letra no dígito verificador e reposiciona o cursor.

máscara de CNPJ alfanumérico
function mascararCnpj(valor) {
  // 1. só letras e números, sempre em maiúsculas
  const limpo = String(valor).toUpperCase().replace(/[^0-9A-Z]/g, '').slice(0, 14);

  // 2. as duas últimas posições só aceitam número
  const base = limpo.slice(0, 12);
  const dv = limpo.slice(12).replace(/\D/g, '');
  const completo = base + dv;

  // 3. monta a pontuação progressivamente
  let saida = completo.slice(0, 2);
  if (completo.length > 2) saida += '.' + completo.slice(2, 5);
  if (completo.length > 5) saida += '.' + completo.slice(5, 8);
  if (completo.length > 8) saida += '/' + completo.slice(8, 12);
  if (completo.length > 12) saida += '-' + completo.slice(12, 14);

  return saida;
}

const campo = document.querySelector('#cnpj');

campo.addEventListener('input', (evento) => {
  const noFim = campo.selectionStart === campo.value.length;
  campo.value = mascararCnpj(campo.value);
  // mantém o cursor no fim quando o usuário está digitando normalmente
  if (noFim) campo.setSelectionRange(campo.value.length, campo.value.length);
});

// cobre colagem com formato estranho e preenchimento automático
campo.addEventListener('change', () => {
  campo.value = mascararCnpj(campo.value);
});

Nas bibliotecas mais usadas

imask, maska, cleave e jquery mask
// IMask — 'a' aceita letra, '0' aceita dígito, '*' aceita ambos
IMask(document.querySelector('#cnpj'), {
  mask: '**.***.***/****-00',
  prepare: (valor) => valor.toUpperCase(),
  definitions: { '*': /[0-9A-Za-z]/ },
});

// Maska (Vue/vanilla) — '#' dígito, '@' letra, '*' alfanumérico
// <input v-maska data-maska="**.***.***/****-##" data-maska-tokens="*:[0-9A-Za-z]|#:[0-9]">

// Cleave.js
new Cleave('#cnpj', {
  blocks: [2, 3, 3, 4, 2],
  delimiters: ['.', '.', '/', '-'],
  uppercase: true,
});

// jQuery Mask Plugin — 'S' letra, '0' dígito, 'A' alfanumérico
$('#cnpj').mask('AA.AAA.AAA/AAAA-00', {
  translation: { A: { pattern: /[0-9A-Za-z]/ } },
  onKeyPress: (v, e, campo) => campo.val(v.toUpperCase()),
});
angular (ngx-mask) e react
// Angular com ngx-mask — 'S' letra, '0' dígito
// <input mask="SS.SSS.SSS/SSSS-00" [validation]="false" oninput="this.value = this.value.toUpperCase()">
// No módulo:
provideNgxMask({ patterns: { S: { pattern: new RegExp('[0-9A-Za-z]') } } });

// React sem biblioteca — controlado, usando a função mascararCnpj acima
export function CampoCnpj() {
  const [valor, setValor] = useState('');

  return (
    <input
      value={valor}
      inputMode="text"
      autoCapitalize="characters"
      maxLength={18}
      placeholder="00.000.000/0000-00"
      onChange={(evento) => setValor(mascararCnpj(evento.target.value))}
    />
  );
}
delphi (TMaskEdit)
// Antes (só dígitos):
edtCnpj.EditMask := '!99.999.999/9999-99;1;_';

// Depois (letras e números nas 12 primeiras posições):
edtCnpj.EditMask := '!CC.CCC.CCC/CCCC-99;1;_';

// Na TMaskEdit do Delphi:
//   9 = dígito opcional   0 = dígito obrigatório
//   C = caractere obrigatório qualquer   A = alfanumérico obrigatório
//   > força maiúsculas do ponto em diante
edtCnpj.EditMask := '!>CC.CCC.CCC/CCCC-99;1;_';
Máscara é conforto, não validação. Todo campo mascarado ainda precisa passar pelo cálculo do dígito verificador no envio — e no servidor, porque a máscara do cliente pode ser burlada.

Detalhes de usabilidade que fazem diferença

Continue por aqui

Dúvidas sobre a máscara

A máscara do CNPJ mudou com o formato alfanumérico?

A pontuação continua idêntica: 00.000.000/0000-00. O que muda é o conjunto de caracteres aceitos — as 12 primeiras posições agora recebem letras, como em 12.ABC.345/01DE-35. Máscaras que forçam dígito (9, 0 ou #) em todas as posições precisam ser trocadas.

Devo converter automaticamente para maiúsculas enquanto o usuário digita?

Sim. É o comportamento esperado e evita confusão, já que o cálculo do dígito verificador só funciona em maiúsculas. Faça a conversão no evento de digitação e também no envio do formulário.

Qual o maxlength correto do campo?

18 se o campo exibe a máscara (14 caracteres + 4 separadores) e 14 se você trabalha sem pontuação. Guarde sempre os 14 caracteres limpos no banco.

Preciso bloquear letras nas duas últimas posições?

É a melhor experiência: como os dígitos verificadores são numéricos, filtrar letras ali evita que o usuário chegue ao fim do preenchimento para só então receber um erro.