# Address Input

Search for an address or enter country-specific details.

---

## Search and edit

Type `Lemon` to try the mock search. Select an address to fill and review the remaining fields.

```tsx
'use client';

import { useId, useState } from 'react';
import {
  AddressInput,
  Select,
  type AddressValue,
} from '@vercel/geistcn/components';
import {
  createFixtureProvider,
  type FixtureScenario,
} from './fixture-provider';

function AddressDemo({ scenario }: { scenario: FixtureScenario }) {
  const [address, setAddress] = useState<Partial<AddressValue>>({
    country: 'US',
  });
  const [provider] = useState(() => createFixtureProvider(scenario));
  return (
    <AddressInput
      provider={provider}
      value={address}
      onChange={setAddress}
      countries={['US', 'CA', 'AU', 'DE', 'HK', 'AE']}
    />
  );
}

export function Component() {
  const [scenario, setScenario] = useState<FixtureScenario>('normal');
  const simulationId = useId();
  return (
    <div className="gap-6 w-full max-w-[400px] flex flex-col">
      <Select
        id={simulationId}
        label="Simulation"
        value={scenario}
        onChange={(event) =>
          setScenario(event.currentTarget.value as FixtureScenario)
        }
      >
        <option value="normal">Typical connection</option>
        <option value="slow">Slow connection</option>
        <option value="many">Long list (8 suggestions)</option>
        <option value="empty">No suggestions</option>
        <option value="search-error">Search unavailable</option>
        <option value="details-error">Address details unavailable</option>
      </Select>
      <AddressDemo key={scenario} scenario={scenario} />
    </div>
  );
}
```

## Live Google search

Google Places search, available in development and preview environments.

```tsx
'use client';

import { useState } from 'react';
import {
  AddressInput,
  Note,
  type AddressValue,
} from '@vercel/geistcn/components';
import { createGoogleAddressProvider } from '@pyra/components/address-input/google-provider';

const apiKey = process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY;

export function Component() {
  const [address, setAddress] = useState<Partial<AddressValue>>({
    country: 'US',
  });
  const [provider] = useState(() => createGoogleAddressProvider({ apiKey }));

  return (
    <div className="flex w-full max-w-[400px] flex-col gap-4">
      {!apiKey ? (
        <Note variant="warning">
          Set NEXT_PUBLIC_GOOGLE_MAPS_API_KEY in apps/geist-docs/.env.local and
          restart the dev server to enable live search.
        </Note>
      ) : null}
      <AddressInput
        provider={apiKey ? provider : undefined}
        value={address}
        onChange={setAddress}
        disabled={!apiKey}
      />
    </div>
  );
}
```

## Manual entry

Omit `provider` to show all fields for the selected country.

```tsx
'use client';

import { AddressInput } from '@vercel/geistcn/components';

export function Component() {
  return (
    <div className="w-full max-w-[400px]">
      <AddressInput defaultValue={{ country: 'DE' }} />
    </div>
  );
}
```

## Lookup unavailable

If lookup fails, users can continue with manual entry.

```tsx
'use client';

import { AddressInput } from '@vercel/geistcn/components';
import { unavailableProvider } from './fixture-provider';

export function Component() {
  return (
    <div className="w-full max-w-[400px]">
      <AddressInput
        defaultValue={{ country: 'US' }}
        provider={unavailableProvider}
        countries={['US', 'HK']}
      />
    </div>
  );
}
```

## Validation

Pass field messages through `errors`. Use `getAddressErrors` to check required fields.

```tsx
'use client';

import { useState } from 'react';
import {
  AddressInput,
  Button,
  getAddressErrors,
  type AddressValue,
} from '@vercel/geistcn/components';

export function Component() {
  const [address, setAddress] = useState<Partial<AddressValue>>({
    country: 'US',
  });
  const [submitted, setSubmitted] = useState(false);
  return (
    <form
      className="flex w-full max-w-[400px] flex-col gap-4"
      noValidate
      onSubmit={(event) => {
        event.preventDefault();
        setSubmitted(true);
      }}
    >
      <AddressInput
        value={address}
        onChange={setAddress}
        errors={submitted ? getAddressErrors(address) : undefined}
        countries={['US', 'HK']}
      />
      <Button typeName="submit">Validate Address</Button>
    </form>
  );
}
```
