Tucano v0.37.2

Máscaras

Formata enquanto se digita, confere o dígito verificador de documento e esconde dado sensível. Não troca o campo por outro controle: é comportamento sobre o seu <input>, que continua com o name e com o estilo que o projeto já aplica.

Digite um CPF inválido e saia do campo: o navegador passa a barrar o envio.

Exemplos

Tudo é o mesmo data-tuc-mask com outro formato. O texto de espera sai do gabarito — ninguém escreve 000.000.000-00 à mão.

CNPJ

Aceita o formato novo, com letras.

CPF ou CNPJ

Troca de gabarito pelo tamanho.

Telefone

Fixo com 8 dígitos ou celular com 9.

Celular

Sempre com 9 dígitos.

CEP

cep

Cartão

card, em grupos de quatro.

Data e hora, em texto

date e time — só a máscara, sem calendário.

Moeda sem símbolo

currency, e três casas com data-decimals="3".

Outra moeda

data-currency="USD" sobre o currency.

Gabarito livre

data-tuc-mask="##/##", validade do cartão.

Gabarito com letras

AAA-####: A é letra, # é dígito. Gabarito livre não passa para maiúscula.

Com erro do servidor

aria-invalid="true" no campo.

CNPJ inválido.

Como usar

Marque o <input> com o formato, e ele inicializa sozinho no carregamento e a cada htmx:afterSwap. O componente veste a classe .tuc-input no campo e põe o inputmode numérico quando o gabarito não aceita letra, para o celular abrir o teclado de números.

<input name="cpf"      data-tuc-mask="cpf" data-validate="true">
<input name="document" data-tuc-mask="cpf-cnpj">
<input name="phone"    data-tuc-mask="phone">
<input name="amount"   data-tuc-mask="brl">
<input name="expiry"   data-tuc-mask="##/##">
FormatoResultado
cpf111.444.777-35
cnpj11.222.333/0001-81 — aceita letras nas 12 primeiras posições
cnpj-numericO mesmo, recusando letras
cpf-cnpjUm ou outro, pelo tamanho
phone(69) 3344-5566 ou (69) 99988-7766
mobile(69) 99988-7766
cep69900-000
date time25/12/2026 · 14:30
card4111 1111 1111 1111
realR$ 1.234,50
currency1.234,50, sem símbolo — com data-currency, o da moeda
gabarito livre# dígito, A letra, * os dois; o resto entra como está
AtributoPadrãoPara quê
data-tuc-mask—Nome do formato ou gabarito livre
data-validatefalseConfere o dígito verificador ao sair do campo
data-error-textdo formatoMensagem do navegador quando a validação reprova
data-decimals2Casas decimais na moeda
data-currency—Código da moeda, como BRL ou USD
data-tuc-reveal—Olho de mostrar e ocultar; o valor escolhe o modo
data-reveal-visible2Caracteres à mostra no modo end
data-reveal-modepelo campoend, email ou all

No formulário do Django

class CustomerForm(forms.ModelForm):
    class Meta:
        model = Customer
        fields = ["document", "phone", "credit_limit"]
        widgets = {
            "document": forms.TextInput(attrs={"data-tuc-mask": "cpf-cnpj", "data-validate": "true"}),
            "phone": forms.TextInput(attrs={"data-tuc-mask": "phone"}),
            "credit_limit": forms.TextInput(attrs={"data-tuc-mask": "brl"}),
        }

O campo posta o texto como está na tela: 111.444.777-35, R$ 1.234,50. Limpe no clean_ — a validação do navegador protege a tela, não o servidor.

def clean_document(self):
    return re.sub(r"[^0-9A-Z]", "", self.cleaned_data["document"].upper())

def clean_credit_limit(self):
    text = re.sub(r"[^\d,]", "", self.cleaned_data["credit_limit"])
    return Decimal(text.replace(",", ".")) if text else None

Em JavaScript

const m = new Tucano.Mask('#amount', { format: 'brl' });
m.getRaw();          // '123450' — sem pontuação
m.getNumber();       // 1234.5 — só nos formatos de moeda; nos outros, null
m.setValue('99');    // formata e dispara tucano:change
m.isValid();         // confere o dígito verificador, nos formatos que têm
m.destroy();

document.querySelector('#amount').addEventListener('tucano:change', (e) => {
  e.detail.value;    // 'R$ 1.234,50'
  e.detail.raw;      // '123450'
  e.detail.number;   // 1234.5
});

Os utilitários por trás da máscara também saem prontos, para validar ou formatar fora de um campo:

Tucano.mask.validateCPF('111.444.777-35')              // true
Tucano.mask.validateCNPJ('11.222.333/0001-81')         // true
Tucano.mask.validateCpfCnpj('123.456.789-01')          // false
Tucano.mask.format('12345678901', 'cpf')               // '123.456.789-01'
Tucano.mask.applyCurrency('12345', { currency: 'BRL' }) // 'R$ 123,45'
Tucano.mask.maskEmail('contato@empresa.com.br')        // 'c••••••@empresa.com.br'

Validação

Com data-validate, o dígito verificador é conferido ao sair do campo. Reprovado, o campo recebe aria-invalid="true" e setCustomValidity, e o próprio navegador barra o envio — sem uma linha no projeto.

E o acerto aparece na hora: assim que o valor fica completo e certo, o campo fica verde, sem esperar sair dele. O erro espera — digitando, um CPF pela metade nunca fica vermelho; ele só é acusado ao sair do campo, e some de novo quando a pessoa volta a corrigir. O verde é o atributo data-tuc-valid, que o CSS pinta com --tuc-success.

Valem cpf, cnpj, cnpj-numeric e cpf-cnpj; os outros formatos não têm dígito para conferir. Campo vazio passa: obrigatoriedade é do required. Enquanto se digita o erro some, e ao voltar ao campo também — inclusive a marca que veio do servidor, porque a pessoa está corrigindo.

<input name="cpf" data-tuc-mask="cpf" data-validate="true" data-error-text="Confira o CPF">

CNPJ alfanumérico

O formato novo mantém as 14 posições e a mesma máscara: as 12 primeiras aceitam letras, as 2 últimas seguem numéricas, e o dígito verificador usa o código ASCII menos 48 — o que deixa o cálculo antigo valendo para CNPJ só de números. O cnpj aceita os dois e passa as letras para maiúscula; cnpj-numeric recusa letras, para quem ainda não pode recebê-las. Confirme a data de vigência na Nota Técnica da Receita antes de exigir em produção.

Campo sensível

O data-tuc-reveal põe um olho para mostrar e ocultar. Campo que já chega preenchido nasce oculto, com só o fim à mostra; campo vazio nasce visível, porque quem digita precisa ver. A senha é a exceção: nasce sempre oculta.

CPF de um cadastro

Modo end, com dois à mostra.

Cartão

data-reveal-visible="4" guarda os quatro últimos.

E-mail

Em type="email", guarda o domínio.

Chave de API

data-tuc-reveal="all" não mostra nada.

Senha

Em type="password" o olho só troca o type.

Vazio

Nasce visível; o olho esconde depois de digitar.

ModoQuandoResultado
end, o padrãoDocumento, cartão, conta, telefone•••• •••• •••• 1234
emailAutomático em type="email"j•••••••••@empresa.com.br
allToken, chave de API••••••••••••••••••••
<input name="cpf" value="111.444.777-35" data-tuc-mask="cpf" data-tuc-reveal>
<input name="card" data-tuc-mask="card" data-tuc-reveal data-reveal-visible="4">
<input name="api_key" data-tuc-reveal="all">
<input type="email" name="email" data-tuc-reveal>
<input type="password" name="password" data-tuc-reveal>

O que o formulário posta não muda por estar oculto. Fora do type="password", o name passa para um <input type="hidden"> com o valor real, e o campo visível mostra os pontos. Enquanto oculto, o campo é só leitura: digitar em cima dos pontos escreveria por cima do valor sem a pessoa perceber. Os separadores continuam no lugar, para a forma seguir reconhecível: •••.•••.•••-35.

Com máscara, o escondido leva o valor sem pontuação

Num campo com data-tuc-mask e data-tuc-reveal, o que chega no servidor é 11144477735, e não 111.444.777-35 — é o getRaw(). Sem máscara, vai o texto como foi digitado.

Por que nascer oculto, e por que o e-mail é ao contrário

Print de tela, gravação de suporte, alguém olhando por cima do ombro: o dado completo aparecia sem ninguém pedir. Nascer oculto é a diferença entre expor por padrão e expor por escolha. No e-mail o domínio é o que ajuda a reconhecer a conta e a parte local é o que identifica a pessoa — guardar o fim revelaria om.br e esconderia o útil. Sem @, ele esconde tudo.

Texto solto na tela

Nem todo dado sensível está num campo: o CPF na tela de um cliente, o cartão numa célula de tabela, a chave de API num parágrafo. O data-tuc-reveal vale em qualquer elemento, nos mesmos modos, e junto com data-tuc-format. O texto nasce escondido, com o olho ao lado.

ClienteCPFCartãoE-mail
João Silva 11144477735 4111 1111 1111 1234 joao.silva@empresa.com.br

Chave de API: sk_live_a1b2c3d4e5f6

<td><span data-tuc-format="cpf" data-tuc-reveal>{{ customer.cpf }}</span></td>
<td><span data-tuc-reveal data-reveal-visible="4">{{ card.number }}</span></td>
<p>Chave de API: <span data-tuc-reveal="all">{{ api_key }}</span></p>

Na tela, esconder é só visual

O valor inteiro continua no HTML: quem abre o código da página vê. Serve contra print, gravação e quem olha por cima do ombro. Se o dado não pode chegar ao navegador, esconda no servidor e mande só o que pode aparecer, como os quatro últimos dígitos do cartão.

Só para exibir

Para o que já vem do banco e não se edita, não precisa de campo: data-tuc-format formata o texto do próprio elemento.

MarcaçãoNa tela
data-tuc-format="cpf" · 1234567890112345678901
data-tuc-format="cnpj" · 1122233300018111222333000181
data-tuc-format="cnpj" · 12ABC34501DE3512ABC34501DE35
data-tuc-format="phone" · 6999988776669999887766
data-tuc-format="cep" · 6990000069900000
data-tuc-format="brl" · 1234.51234.5
data-tuc-format="currency" data-decimals="3" · 12.512.5
<span data-tuc-format="cpf">{{ customer.cpf }}</span>
<span data-tuc-format="brl">{{ order.total }}</span>
<span data-tuc-format="phone" data-value="{{ customer.phone }}"></span>

Aceita cpf, cnpj, cpf-cnpj, phone, mobile, cep, card, real, currency e gabarito livre, com data-decimals e data-currency na moeda. O valor sai do texto do elemento ou de data-value. Moeda lê o ponto decimal do banco (1234.5) e também a vírgula. Conteúdo que não preenche o gabarito volta como veio, em vez de sair pela metade e parecer corrompido. Para HTML inserido por outro caminho que não o HTMX, Tucano.autoFormat(element).

Teclado e acessibilidade

A máscara usa o teclado do navegador, sem atalho próprio. O que ela cuida é de o cursor não se perder.

TeclaAção
Backspace DeleteEm cima de um separador, apaga o caractere vizinho, em vez de travar
ColarDescarta o que não cabe: abc111x444.777--35 vira 111.444.777-35
Digitar na moedaEnche da direita para a esquerda, com o cursor sempre no fim
Tab até o olhoÉ um <button>: Enter e Espaço alternam

O olho anuncia "Mostrar" ou "Ocultar" e o estado por aria-pressed. Ao mostrar, o foco vai para o campo. Reprovado na validação, o campo fica com aria-invalid="true", que o leitor de tela lê como inválido.

API

Gerada do código a cada build — se algo não está aqui, não existe.

Marcação
[data-tuc-mask], [data-tuc-reveal] [data-tuc-format]:not([data-tuc-formatted])
Em JS
new Tucano.Mask(alvo, opcoes) Tucano.autoFormat()
Atributos
data-currency data-decimals data-error-text data-reveal-mode data-reveal-visible data-tuc-format data-tuc-mask data-tuc-reveal data-validate data-value
Métodos
getRaw getNumber setValue isValid destroy
Eventos
tucano:change

Opções

OpçãoPadrãoPara quê
formatnullnome de FORMATS ou gabarito livre
validatefalsevalida no blur e bloqueia o submit
decimals2
currencynull'BRL' formata com R$
revealfalseolhinho para mostrar e ocultar
revealVisible2quantos caracteres ficam a mostra no modo 'end'
revealModenull'end' | 'email' | 'all'. null decide pelo campo
localeundefined
errorTextnull
onChangenull