Validar, gerar e formatar CPF em JavaScript
Funções em JavaScript (ES2020) para validar, gerar e formatar CPF com o módulo 11, testes com Vitest ou Jest e como chamar a API do cpf.dev.br.
Validar CPF em JavaScript é uma das tarefas mais copiadas e coladas da internet, e boa parte das versões que circulam tem algum defeito: aceita 111.111.111-11, esquece a regra do resto menor que 2 ou quebra com a pontuação. O código desta página é ES2020 puro, sem dependências, e roda igual no navegador e no Node.js 19 ou mais recente. A lógica é a mesma das ferramentas do site; o passo a passo da conta está no guia do algoritmo do módulo 11.
Validar CPF em JavaScript
A função aceita o CPF com ou sem máscara. Pontos, hífen e espaços são removidos; qualquer outro caractere faz a validação falhar, em vez de ser descartado em silêncio.
const REPETIDO = /^(\d)\1{10}$/;
function calcularDigito(digitos, pesoInicial) {
let soma = 0;
for (let i = 0; i < digitos.length; i++) {
soma += Number(digitos[i]) * (pesoInicial - i);
}
const resto = soma % 11;
return resto < 2 ? 0 : 11 - resto;
}
export function validarCpf(valor) {
const cpf = String(valor ?? '').replace(/[.\-\s]/g, '');
if (!/^\d{11}$/.test(cpf)) return false;
if (REPETIDO.test(cpf)) return false;
const dv1 = calcularDigito(cpf.slice(0, 9), 10);
const dv2 = calcularDigito(cpf.slice(0, 10), 11);
return dv1 === Number(cpf[9]) && dv2 === Number(cpf[10]);
}Três detalhes fazem diferença:
String(valor ?? '')evita exceção quando o campo chega comonull,undefinedou número.- A checagem de repetidos vem antes da conta. Sequências como 111.111.111-11 passam no módulo 11, mas não são consideradas válidas.
resto < 2 ? 0 : 11 - restocobre os restos 0 e 1. Sem isso, CPFs legítimos como 529.982.248-06 seriam recusados.
Com 529.982.247-25, a primeira soma é 295, o resto é 9 e o primeiro dígito é 2; a segunda soma é 347, o resto é 6 e o segundo dígito é 5. A função devolve true. Com 529.982.247-26, o segundo dígito calculado continua sendo 5 e não bate com o 6 informado.
Gerar CPF válido em JavaScript
Para gerar, sorteie nove dígitos, descarte a base repetida e calcule os dois verificadores com a mesma calcularDigito. crypto.getRandomValues existe como global nos navegadores e no Node.js.
function digitoAleatorio() {
return crypto.getRandomValues(new Uint32Array(1))[0] % 10;
}
export function gerarCpf({ formatado = false } = {}) {
let base;
do {
base = '';
for (let i = 0; i < 9; i++) base += digitoAleatorio();
} while (/^(\d)\1{8}$/.test(base));
const dv1 = calcularDigito(base, 10);
const dv2 = calcularDigito(base + dv1, 11);
const cpf = base + dv1 + dv2;
return formatado ? formatarCpf(cpf) : cpf;
}Um CPF gerado assim é válido, mas pode coincidir com um CPF real por acaso. Use-o só em ambientes de teste e em dados fictícios; o guia sobre massa de teste e LGPD explica os cuidados. O nono dígito indica a região fiscal (8 é São Paulo), como mostra o guia das regiões fiscais, caso você precise fixar o estado.
Formatar e limpar CPF em JavaScript
Guarde o CPF só com dígitos e aplique a máscara na exibição. A formatarCpf abaixo também aceita entradas parciais, o que a torna útil em campos com máscara enquanto a pessoa digita.
export function limparCpf(valor) {
return String(valor ?? '').replace(/\D/g, '');
}
export function formatarCpf(valor) {
const d = limparCpf(valor).slice(0, 11);
let saida = d.slice(0, 3);
if (d.length > 3) saida += '.' + d.slice(3, 6);
if (d.length > 6) saida += '.' + d.slice(6, 9);
if (d.length > 9) saida += '-' + d.slice(9, 11);
return saida;
}formatarCpf('52998224725') devolve '529.982.247-25', formatarCpf('5299') devolve '529.9' e limparCpf('529.982.247-25') devolve '52998224725'. limparCpf remove tudo que não é dígito e serve para normalizar antes de gravar. Ela não substitui a validação: limpar “529a982247-25” produz 11 dígitos, mas validarCpf recusa a entrada original. Para integrar com React, Vue ou Angular sem perder a posição do cursor, veja o guia de máscara de CPF.
Testes
Os três casos mínimos são um CPF válido, uma sequência repetida e um CPF com o último dígito errado. Com Vitest, it.each gera um teste por linha; no Jest, o mesmo arquivo funciona trocando o import por @jest/globals.
import { describe, expect, it } from 'vitest';
import { formatarCpf, gerarCpf, limparCpf, validarCpf } from './cpf.js';
describe('validarCpf', () => {
it.each([
['529.982.247-25', true],
['111.111.111-11', false],
['529.982.247-26', false],
])('validarCpf(%s) devolve %s', (cpf, esperado) => {
expect(validarCpf(cpf)).toBe(esperado);
});
});
describe('gerarCpf e formatarCpf', () => {
it('gera CPFs que passam na validação', () => {
for (let i = 0; i < 1000; i++) expect(validarCpf(gerarCpf())).toBe(true);
});
it('formata e limpa de ida e volta', () => {
expect(formatarCpf('52998224725')).toBe('529.982.247-25');
expect(limparCpf('529.982.247-25')).toBe('52998224725');
});
});O guia de erros comuns ao validar CPF tem mais casos de borda para ampliar essa tabela.
Usar a API em vez de reimplementar
Se você não quer manter o algoritmo no seu código, a API do cpf.dev.br valida e gera CPFs por HTTP. Ela não exige chave e aceita até 60 requisições por minuto por IP. O exemplo usa await no nível do módulo, então precisa rodar como ES module: salve como .mjs ou use "type": "module" no package.json.
const resposta = await fetch('https://www.cpf.dev.br/api/v1/cpf/validar/529.982.247-25');
const dados = await resposta.json();
// { valido: true, cpf: '52998224725', formatado: '529.982.247-25', uf: ['ES', 'RJ'] }
const lote = await fetch('https://www.cpf.dev.br/api/v1/cpf/gerar?quantidade=5&uf=SP&formatado=true');
const { cpfs } = await lote.json(); // cinco CPFs com nono dígito 8Para validação de formulário, o código local é melhor: responde na hora e funciona offline. A API compensa em scripts, seeds e pipelines de teste. Para conferir um número à mão, use o validador de CPF ou o gerador de CPF.