Máscara de CPF, CNPJ, CEP e telefone em JavaScript

Uma máscara de formulário põe os pontos, traços e parênteses enquanto a pessoa digita, sem impedir que ela cole o valor já formatado. Este guia traz máscaras de CPF, CNPJ (inclusive o novo formato com letras), CEP e telefone em JavaScript puro, sem biblioteca, os atributos de HTML que ajudam no celular e a formatação para exibição em Python e PHP.

Por Leonardo Gaertner · Publicado em

Como a máscara funciona

A cada tecla, a máscara tira tudo que não é dígito, corta no tamanho máximo e põe a pontuação de novo. Como ela sempre parte dos dígitos, funciona igual para quem digita, quem cola 52998224725 e quem cola 529.982.247-25. Cada regra só aplica a pontuação quando já há dígitos depois dela, então o valor pela metade também sai certo.

A máscara cuida só do formato. Para saber se o número é válido, confira os dígitos verificadores, como no validador de CPF e no validador de CNPJ.

As máscaras em JavaScript

O telefone troca de formato no 11º dígito: com 10 dígitos é fixo, (11) 3123-4567, e com 11 é celular, (11) 91234-5678. O CNPJ aceita letras nas 12 primeiras posições, como no formato alfanumérico que a Receita usa desde julho de 2026.

JavaScript
const soDigitos = (v) => v.replace(/\D/g, '');

// Cada máscara aceita o valor pela metade, para ser aplicada enquanto a pessoa digita
const mascaras = {
  cpf: (v) =>
    soDigitos(v)
      .slice(0, 11)
      .replace(/(\d{3})(\d)/, '$1.$2')
      .replace(/(\d{3})(\d)/, '$1.$2')
      .replace(/(\d{3})(\d{1,2})$/, '$1-$2'),
  // CNPJ numérico e alfanumérico (letras nas 12 primeiras posições)
  cnpj: (v) =>
    v
      .toUpperCase()
      .replace(/[^0-9A-Z]/g, '')
      .slice(0, 14)
      .replace(/^(\w{2})(\w)/, '$1.$2')
      .replace(/^(\w{2})\.(\w{3})(\w)/, '$1.$2.$3')
      .replace(/\.(\w{3})(\w)/, '.$1/$2')
      .replace(/(\w{4})(\w)/, '$1-$2'),
  cep: (v) => soDigitos(v).slice(0, 8).replace(/(\d{5})(\d)/, '$1-$2'),
  // Fixo com 10 dígitos e celular com 11: o formato muda no 11º dígito
  telefone: (v) => {
    const d = soDigitos(v).slice(0, 11);
    if (d.length === 11) return d.replace(/(\d{2})(\d{5})(\d{4})/, '($1) $2-$3');
    return d.replace(/(\d{2})(\d)/, '($1) $2').replace(/(\d{4})(\d)/, '$1-$2');
  },
};

function aplicarMascara(input, tipo) {
  input.addEventListener('input', () => {
    input.value = mascaras[tipo](input.value);
  });
}

Uso: aplicarMascara(document.querySelector("#cpf"), "cpf").

Os atributos de HTML que ajudam

  • Use type="text", e não type="number": o campo de número tira os zeros à esquerda do CEP e do CPF e mostra setas de aumentar e diminuir.
  • inputmode="numeric" abre o teclado numérico no celular para CPF, CEP e telefone. Não use no CNPJ, que agora pode ter letras.
  • autocomplete="postal-code" no CEP e autocomplete="tel-national" no telefone deixam o navegador preencher sozinho.
  • maxlength com o tamanho já formatado: 14 para CPF, 18 para CNPJ, 9 para CEP e 15 para telefone.

Formatar para exibição em Python e PHP

No servidor, guarde só os dígitos e formate na hora de mostrar. As funções abaixo devolvem o valor original quando o tamanho não fecha, para não esconder um dado errado com uma máscara.

Python
import re


def formatar_cpf(valor: str) -> str:
    d = re.sub(r"\D", "", valor)
    return f"{d[:3]}.{d[3:6]}.{d[6:9]}-{d[9:11]}" if len(d) == 11 else valor


def formatar_cnpj(valor: str) -> str:
    c = re.sub(r"[^0-9A-Z]", "", valor.upper())
    return f"{c[:2]}.{c[2:5]}.{c[5:8]}/{c[8:12]}-{c[12:14]}" if len(c) == 14 else valor


def formatar_telefone(valor: str) -> str:
    d = re.sub(r"\D", "", valor)
    if len(d) == 11:
        return f"({d[:2]}) {d[2:7]}-{d[7:]}"
    if len(d) == 10:
        return f"({d[:2]}) {d[2:6]}-{d[6:]}"
    return valor
PHP
<?php
function formatarCpf(string $valor): string
{
    $d = preg_replace('/\D/', '', $valor);
    if (strlen($d) !== 11) {
        return $valor;
    }
    [$a, $b, $c, $dv] = [substr($d, 0, 3), substr($d, 3, 3), substr($d, 6, 3), substr($d, 9, 2)];
    return "$a.$b.$c-$dv";
}

function formatarCep(string $valor): string
{
    $d = preg_replace('/\D/', '', $valor);
    return strlen($d) === 8 ? substr($d, 0, 5) . '-' . substr($d, 5) : $valor;
}

Cuidados

  • Mande para o servidor só os dígitos (remova a máscara antes de enviar) e valide de novo lá. A máscara no navegador não protege nada.
  • Trocar o valor do campo a cada tecla move o cursor para o fim. Se a pessoa corrigir um dígito no meio, ela perde a posição; para a maioria dos formulários isso é aceitável, mas leitores de tela podem anunciar o valor inteiro a cada tecla.
  • Para validar o formato completo, use as expressões do guia de regex para CEP, telefone e e-mail.
  • Para gerar números válidos para testar o formulário, veja como gerar CPF e CNPJ para testes.

Achou um erro neste guia? Avise por e-mail.

Perguntas frequentes

Como fazer máscara de CPF em JavaScript sem biblioteca?

A cada evento input, tire o que não é dígito, corte em 11 dígitos e reponha os pontos e o traço com replace. A função deste guia faz isso e funciona tanto digitando quanto colando o CPF formatado.

Como fazer máscara de telefone que aceite fixo e celular?

Formate como fixo, (11) 3123-4567, até 10 dígitos, e troque para celular, (11) 91234-5678, quando a pessoa digitar o 11º. É o que a máscara deste guia faz.

A máscara de CNPJ precisa mudar por causa do CNPJ alfanumérico?

Precisa aceitar letras nas 12 primeiras posições e não usar teclado só numérico. A pontuação continua a mesma: 12.ABC.345/01DE-35.

Devo salvar o CPF com ou sem máscara no banco?

Sem máscara, só com os dígitos. Assim a busca e a comparação funcionam sempre, e a máscara é aplicada na hora de exibir.