# How to apply a CPF, ZIP code, or date mask

> Automatically format CPF, ZIP codes, and dates with a mask and read back the clean digits.

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

# How to apply a CPF, ZIP code, or date mask

**Purpose.** Automatically format typing with separators (dots, dashes, slashes) showing `123.456.789-00` while the user types only the digits, and later retrieve the clean value (`12345678900`).

## APIs used
- `campo.<TextFieldStyle>getStyle().mask("999.999.999-99".toCharArray())` — defines the mask pattern. `9` = digit position; any other character is a literal inserted automatically (`.`, `-`, `/`).
- `.mode(EditMode.NUMERIC, true)` — turns on numeric mode AND `maskedEdit` (second parameter `true`). Without `maskedEdit` the mask is not applied. Order matters: call `mask(...)` and `mode(...)` together.
- `TextField.getText()` — returns the text WITH the mask (`"123.456.789-00"`), ideal for displaying/saving formatted.
- `TextField.getTextWithoutMask()` — returns only the digits of the `9` positions (`"12345678900"`), ideal for validating and sending to the backend.

> For **dates**, prefer `setMode(EditMode.DATE, true)`: it automatically derives the mask from the locale (`LocaleFormats.dateSeparator` and `LocaleFormats.dateFormat`, e.g., `dd/MM/yyyy` or `yyyy-MM-dd`) and also opens the DatePicker. See the [Date and time](/docs/cookbook/forms/data-e-hora) recipe.

> Mind the order in `mode(EditMode.NUMERIC, true)`: the `NUMERIC`/`NORMAL` mode only recalculates `maxLength` from the mask if the mask is already defined. Set `mask(...)` **before** or in the same fluent chain.

## Complete example (copy, paste, and run)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;   // TextFieldStyle (config on the style)

/** Runnable main screen. Point the launcher (classname) and run: 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);
   }
}
```

> The snippet below shows **only the core**. To run it, place it in the `MainWindow` skeleton above.

## Minimal snippet
```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"
   // validates cpfLimpo.length() == 11 and submits
});
```

## Dig deeper
- [Masks and keyboards](/docs/ui/forms-and-input/masks-and-keyboards) · [Text fields](/docs/ui/forms-and-input/text-fields)
- Sibling recipes: [Validate a field](/docs/cookbook/forms/validar-campo) · [Currency mask](/docs/cookbook/forms/mascara-moeda) · [Date and time](/docs/cookbook/forms/data-e-hora)
- Canonical source: Chapter 14 — Basic widgets · [Enums (UIConstants)](/docs/reference/enums-uiconstants)
