Validar, gerar e formatar CNPJ em JavaScript
Funções em JavaScript para validar, gerar e formatar CNPJ numérico e alfanumérico, com testes no Vitest e chamada à API do cpf.dev.br.
O CNPJ alfanumérico mudou a regra que quase todo validador em JavaScript assume: os 12 primeiros caracteres podem ser letras de A a Z, e só os dois dígitos verificadores continuam sendo números. A boa notícia é que o cálculo é o mesmo para os dois formatos, desde que cada caractere seja convertido pelo código ASCII menos 48. O código desta página é JavaScript puro, sem dependências, e roda no navegador e no Node.js. O que muda no resto do sistema (colunas, máscaras, integrações) está no guia CNPJ alfanumérico: o que muda no seu sistema.
Validar CNPJ em JavaScript (numérico e alfanumérico)
const PESOS_1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
const PESOS_2 = [6, ...PESOS_1];
function calcularDigito(base, pesos) {
let soma = 0;
for (let i = 0; i < base.length; i++) {
soma += (base.charCodeAt(i) - 48) * pesos[i];
}
const resto = soma % 11;
return resto < 2 ? 0 : 11 - resto;
}
export function validarCnpj(valor) {
const cnpj = String(valor ?? '').toUpperCase().replace(/[.\/\-\s]/g, '');
if (!/^[A-Z0-9]{12}[0-9]{2}$/.test(cnpj)) return false;
if (/^(.)\1{11}/.test(cnpj)) return false;
const base = cnpj.slice(0, 12);
const dv1 = calcularDigito(base, PESOS_1);
const dv2 = calcularDigito(base + dv1, PESOS_2);
return cnpj.slice(12) === String(dv1) + String(dv2);
}Pontos que costumam dar errado:
toUpperCase()vem antes de tudo. Assim12.abc.345/01de-35é tratado igual a12.ABC.345/01DE-35.- Só pontos, barra, hífen e espaços são removidos. Qualquer outro símbolo deixa a string fora do padrão e a função devolve
false, em vez de descartá-lo em silêncio. [A-Z0-9]{12}[0-9]{2}aceita letras na raiz e na ordem, mas exige números nos verificadores.charCodeAt(i) - 48dá 0 a 9 para os dígitos e 17 a 42 para as letras (A vale 17, Z vale 42). Para um CNPJ só com números, o resultado é idêntico ao cálculo antigo.- Bases repetidas são recusadas. 00.000.000/0000-00 fecha a conta, mas não é um CNPJ válido.
Com 11.222.333/0001-81, a primeira soma é 102, o resto é 3 e o primeiro dígito é 8; a segunda soma é 120, o resto é 10 e o segundo dígito é 1. Com 12.ABC.345/01DE-35, as somas são 459 e 424, os restos 8 e 6 e os dígitos 3 e 5. A calculadora de dígitos do CNPJ mostra cada produto dessa conta.
Gerar CNPJ válido em JavaScript
O gerador sorteia 12 caracteres, descarta a base repetida e calcula os verificadores com a mesma calcularDigito. Com alfanumerico: true, o alfabeto passa a ter 36 símbolos.
const DIGITOS = '0123456789';
const ALFANUMERICOS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
function sortear(alfabeto, n) {
const sorteio = crypto.getRandomValues(new Uint32Array(n));
return Array.from(sorteio, (x) => alfabeto[x % alfabeto.length]).join('');
}
export function gerarCnpj({ alfanumerico = false, formatado = false } = {}) {
const alfabeto = alfanumerico ? ALFANUMERICOS : DIGITOS;
let base;
do {
base = sortear(alfabeto, 12);
} while (/^(.)\1{11}$/.test(base));
const dv1 = calcularDigito(base, PESOS_1);
const dv2 = calcularDigito(base + dv1, PESOS_2);
const cnpj = base + dv1 + dv2;
return formatado ? formatarCnpj(cnpj) : cnpj;
}O CNPJ gerado passa na validação, mas pode coincidir com um CNPJ real por acaso. Use-o só em testes e dados fictícios. Se o teste precisa de uma matriz, fixe a ordem em 0001 em vez de sorteá-la; o guia da estrutura do CNPJ explica raiz, ordem e dígitos. Para muitos números de uma vez, o gerador de CNPJ em lote exporta em CSV, JSON ou SQL.
Formatar e limpar CNPJ em JavaScript
export function limparCnpj(valor) {
return String(valor ?? '').toUpperCase().replace(/[^A-Z0-9]/g, '');
}
export function formatarCnpj(valor) {
const c = limparCnpj(valor).slice(0, 14);
let saida = c.slice(0, 2);
if (c.length > 2) saida += '.' + c.slice(2, 5);
if (c.length > 5) saida += '.' + c.slice(5, 8);
if (c.length > 8) saida += '/' + c.slice(8, 12);
if (c.length > 12) saida += '-' + c.slice(12, 14);
return saida;
}formatarCnpj('12abc34501de35') devolve '12.ABC.345/01DE-35', e aplicar a função de novo no resultado não muda nada. Como aceita entrada parcial ('1122' vira '11.22'), ela serve para máscara de campo enquanto a pessoa digita. Lembre de trocar o inputmode="numeric" do campo por texto, senão o teclado do celular não mostra letras. Para conferir padrões de máscara em expressões regulares, veja o guia de regex de CNPJ.
Testes
Os quatro casos abaixo cobrem um CNPJ numérico válido, um alfanumérico válido, um dígito errado e uma base repetida. No Jest, o mesmo arquivo funciona trocando o import por @jest/globals.
import { describe, expect, it } from 'vitest';
import { formatarCnpj, gerarCnpj, limparCnpj, validarCnpj } from './cnpj.js';
describe('validarCnpj', () => {
it.each([
['11.222.333/0001-81', true],
['12.ABC.345/01DE-35', true],
['11.222.333/0001-82', false],
['00.000.000/0000-00', false],
])('validarCnpj(%s) devolve %s', (cnpj, esperado) => {
expect(validarCnpj(cnpj)).toBe(esperado);
});
});
describe('gerarCnpj e formatarCnpj', () => {
it.each([false, true])('gera CNPJs válidos (alfanumerico: %s)', (alfanumerico) => {
for (let i = 0; i < 1000; i++) {
expect(validarCnpj(gerarCnpj({ alfanumerico }))).toBe(true);
}
});
it('formata de forma idempotente e limpa', () => {
expect(formatarCnpj('12abc34501de35')).toBe('12.ABC.345/01DE-35');
expect(formatarCnpj('12.ABC.345/01DE-35')).toBe('12.ABC.345/01DE-35');
expect(limparCnpj('11.222.333/0001-81')).toBe('11222333000181');
});
});Mais combinações de letras e números para ampliar a tabela estão nos exemplos de CNPJ alfanumérico para teste.
Usar a API em vez de reimplementar
A API do cpf.dev.br valida e gera CNPJs por HTTP, sem chave, com limite de 60 requisições por minuto por IP. Envie o CNPJ sem máscara ou passe-o por encodeURIComponent, que transforma a barra em %2F. O exemplo usa await no nível do módulo, então salve como .mjs.
const resposta = await fetch('https://www.cpf.dev.br/api/v1/cnpj/validar/12ABC34501DE35');
const dados = await resposta.json();
// { valido: true, cnpj: '12ABC34501DE35', formatado: '12.ABC.345/01DE-35',
// formato: 'alfanumerico', raiz: '12ABC345', ordem: '01DE', matriz: false }
const url = 'https://www.cpf.dev.br/api/v1/cnpj/gerar?quantidade=5&formato=alfanumerico&formatado=true';
const { cnpjs } = await (await fetch(url)).json();Em formulários, a função local é melhor: responde na hora e não depende de rede. A API compensa em scripts, seeds e pipelines. Para conferir um número à mão, use o validador de CNPJ ou o gerador de CNPJ.