# Como aplicar máscara de CPF, CEP ou data

> Formatar automaticamente CPF, CEP e datas com máscara e ler os dígitos limpos.

Source: https://crossfly.dev/pt/docs/cookbook/forms/mascara-cpf — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Como aplicar máscara de CPF, CEP ou data

**Propósito.** Formatar a digitação automaticamente com separadores (pontos, traços, barras) mostrando `123.456.789-00` enquanto o usuário digita só os dígitos, e recuperar depois o valor limpo (`12345678900`).

## APIs usadas
- `campo.<TextFieldStyle>getStyle().mask("999.999.999-99".toCharArray())` — define o padrão da máscara. `9` = posição de dígito; qualquer outro caractere é um literal inserido automaticamente (`.`, `-`, `/`).
- `.mode(EditMode.NUMERIC, true)` — liga o modo numérico E o `maskedEdit` (segundo parâmetro `true`). Sem o `maskedEdit` a máscara não é aplicada. Ordem importa: chame `mask(...)` e `mode(...)` juntos.
- `TextField.getText()` — devolve o texto COM máscara (`"123.456.789-00"`), ideal para exibir/salvar formatado.
- `TextField.getTextWithoutMask()` — devolve só os dígitos das posições `9` (`"12345678900"`), ideal para validar e enviar ao backend.

> Para **datas**, prefira `setMode(EditMode.DATE, true)`: ele deriva a máscara automaticamente do locale (`LocaleFormats.dateSeparator` e `LocaleFormats.dateFormat`, ex.: `dd/MM/yyyy` ou `yyyy-MM-dd`) e ainda abre o DatePicker. Veja a receita [Data e hora](/docs/cookbook/forms/data-e-hora).

> Atenção à ordem em `mode(EditMode.NUMERIC, true)`: o modo `NUMERIC`/`NORMAL` só recalcula o `maxLength` a partir da máscara se a máscara já estiver definida. Defina `mask(...)` **antes** ou na mesma cadeia fluente.

## Exemplo completo (copiar, colar e rodar)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;   // TextFieldStyle (config no estilo)

/** Tela principal executável. Aponte o launcher (classname) e rode: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      // CPF: 123.456.789-00
      TextField cpf = new TextField("");
      cpf.caption("CPF");
      cpf.<TextFieldStyle>getStyle()
         .mask("999.999.999-99".toCharArray())
         .mode(EditMode.NUMERIC, true);   // NUMERIC + maskedEdit

      // CEP: 12345-678
      TextField cep = new TextField("");
      cep.caption("CEP");
      cep.<TextFieldStyle>getStyle()
         .mask("99999-999".toCharArray())
         .mode(EditMode.NUMERIC, true);

      Label resultado = new Label("");

      Button enviar = new Button("Enviar");
      enviar.onAction(o ->
      {
         String cpfFormatado = cpf.getText();            // "123.456.789-00"
         String cpfLimpo     = cpf.getTextWithoutMask(); // "12345678900"
         if (cpfLimpo.length() != 11)
         {
            Hint.show("CPF deve ter 11 dígitos", 2000);
            return;
         }
         resultado.setText(cpfFormatado + " · CEP: " + cep.getText());
      });

      add(LAY_FILL, cpf);
      add(LAY_FILL, cep);
      add(LAY_AUTO, enviar);
      add(LAY_FILL, resultado);
   }
}
```

> O trecho abaixo mostra **só o miolo**. Para rodar, coloque-o no esqueleto `MainWindow` acima.

## Trecho mínimo
```java
import dev.crossfly.ui.*;
import dev.crossfly.ui.style.*;
import static dev.crossfly.ui.UIConstants.EditMode;

// CPF: 123.456.789-00
TextField cpf = new TextField("");
cpf.caption("CPF");
cpf.<TextFieldStyle>getStyle()
   .mask("999.999.999-99".toCharArray())
   .mode(EditMode.NUMERIC, true);   // NUMERIC + maskedEdit

// CEP: 12345-678
TextField cep = new TextField("");
cep.caption("CEP");
cep.<TextFieldStyle>getStyle()
   .mask("99999-999".toCharArray())
   .mode(EditMode.NUMERIC, true);

Button enviar = new Button("Enviar");
enviar.onAction(o ->
{
   String cpfFormatado = cpf.getText();            // "123.456.789-00"
   String cpfLimpo     = cpf.getTextWithoutMask(); // "12345678900"
   // valida cpfLimpo.length() == 11 e envia
});
```

## Aprofunde-se
- [Máscaras e teclados](/docs/ui/forms-and-input/masks-and-keyboards) · [Campos de texto](/docs/ui/forms-and-input/text-fields)
- Receitas irmãs: [Validar um campo](/docs/cookbook/forms/validar-campo) · [Máscara de moeda](/docs/cookbook/forms/mascara-moeda) · [Data e hora](/docs/cookbook/forms/data-e-hora)
- Fonte canônica: Capítulo 14 — Widgets básicos · [Enums (UIConstants)](/docs/reference/enums-uiconstants)
