# CEP Field

> Postal code entry that masks, looks up the address, and reports the result.

- Category: Brazil
- Kind: component
- Page: https://uaiblocks.dev/components/cep-field
- Registry item: https://uaiblocks.dev/r/cep-field.json
- Source: https://github.com/victor-teles/uai/blob/main/src/registry/uai/components/cep-field.tsx

## Install

```bash
bunx shadcn@latest add https://uaiblocks.dev/r/cep-field.json
```

## Usage

```tsx
"use client";

import { useState } from "react";
import {
  CepField,
  CepFieldAddress,
  CepFieldControl,
  CepFieldInput,
  CepFieldLabel,
  CepFieldLookup,
  CepFieldMessage,
  type CepFieldStatus,
  type CepFieldVariant,
} from "@/components/ui/uai/cep-field";

type Address = { street: string; district: string; city: string; state: string };

const addresses: Record<string, Address> = {
  "01310100": {
    street: "Avenida Paulista",
    district: "Bela Vista",
    city: "São Paulo",
    state: "SP",
  },
  "20040002": {
    street: "Rua da Assembleia",
    district: "Centro",
    city: "Rio de Janeiro",
    state: "RJ",
  },
};

export function CepFieldPreview({ variant = "rounded" }: { variant?: CepFieldVariant }) {
  const [status, setStatus] = useState<CepFieldStatus>("idle");
  const [address, setAddress] = useState<Address | null>(null);

  const lookup = (cep: string) => {
    setStatus("loading");
    window.setTimeout(() => {
      const match = addresses[cep];
      setAddress(match ?? null);
      setStatus(match ? "found" : cep === "99999999" ? "error" : "not-found");
    }, 700);
  };

  return (
    <CepField
      variant={variant}
      status={status}
      onValueChange={() => setStatus("idle")}
      onLookup={lookup}
    >
      <CepFieldLabel>CEP de entrega</CepFieldLabel>
      <CepFieldControl>
        <CepFieldInput name="cep" />
        <CepFieldLookup />
      </CepFieldControl>
      <CepFieldMessage>
        {status === "idle" ? "Experimente 01310-100 ou 20040-002." : undefined}
      </CepFieldMessage>
      {address && (
        <CepFieldAddress>
          <span>{address.street}</span>
          <span>
            {address.district}, {address.city} – {address.state}
          </span>
        </CepFieldAddress>
      )}
    </CepField>
  );
}
```

## Anatomy

- `CepField`
  - `CepFieldLabel`
  - `CepFieldControl`
    - `CepFieldInput`
    - `CepFieldLookup`
  - `CepFieldMessage`
    - `CepFieldAddress`

## Accessibility

- The input uses the numeric keyboard and the postal-code autocomplete token.
- Lookup runs once when eight digits are entered, and again from Enter or the Buscar button.
- Progress, not-found, and failure messages live in a polite status region linked to the input.
- The resolved address renders as an address element after a successful lookup.
