> ## Documentation Index
> Fetch the complete documentation index at: https://docs.whop.com/llms.txt
> Use this file to discover all available pages before exploring further.

# AddressElement

> Collects a billing or shipping address with per-country formats — the field set, order, required flags, and postal-code validation adapt to the selected country — plus address autocomplete on the street field. Drive your own forms off `onChange`, or call `validate()` / `getValues()` on the handle.

{/* whop-elements-docs-channel: upcoming */}

<Info>**Upcoming** — generated from the latest merged element source; documents unreleased development. Use the channel picker at the top of the sidebar for the docs of a published release.</Info>

{/* whop-elements-since: unreleased */}*In development — not yet part of a stable release.*

Belongs to the [`Payments`](/elements/upcoming/payments/overview) group. Render `<AddressElement />` inside it (React), or call `payments.create('address', { … })` on the handle (vanilla) — consumer props and `on<Event>` callbacks both go in the create options / JSX props.

## Preview

A live, interactive demo of this element with sample data:

<div data-whop-demo-shell style={{ position: "relative", minHeight: "320px", transition: "min-height 200ms ease" }}>
  <div data-whop-demo-skeleton style={{ position: "absolute", inset: "0", borderRadius: "12px", background: "rgba(140, 140, 140, 0.12)", pointerEvents: "none", transition: "opacity 200ms ease" }} />

  <iframe data-whop-demo src="https://js.whop.cloud/elements/amber/payments/address/en/demo/index.html" title="AddressElement demo" height="320" allow="payment; publickey-credentials-get; clipboard-write" style={{ position: "relative", width: "100%", border: "0", borderRadius: "12px", background: "transparent", colorScheme: "normal" }} />
</div>

## Usage

<div data-whop-usage="payments/address">
  <CodeGroup>
    ```tsx React theme={null}
    import { WhopElements, Payments, AddressElement } from "@whop/elements-react";
    import { loadWhop } from "@whop/elements";

    function Example() {
      return (
        <WhopElements elements={loadWhop()}>
          <Payments /* options */>
            <AddressElement onChange={(payload) => console.log("change", payload)} />
          </Payments>
        </WhopElements>
      );
    }
    ```

    ```html Vanilla theme={null}
    <script src="https://js.whop.cloud/elements/amber/elements.js" data-whop-elements></script>
    <script type="module">
      const payments = window.WhopElements().payments.create({ /* options */ });
      payments.create('address', { onChange: (payload) => console.log("change", payload) }).mount('#payments-address');
    </script>
    ```
  </CodeGroup>
</div>

## Props

<ResponseField name="layout" type="&#x22;full&#x22; | &#x22;compact&#x22;">
  `full` (default) stacks labeled fields; `compact` fuses them into one dense bordered group with placeholder labels. Defaults to `"full"`.
</ResponseField>

<ResponseField name="name" type="&#x22;split&#x22; | &#x22;combined&#x22; | &#x22;none&#x22;">
  The name row: one full-name field (default), split first/last fields, or none. Defaults to `"combined"`.
</ResponseField>

<ResponseField name="line2" type="&#x22;never&#x22; | &#x22;toggle&#x22; | &#x22;always&#x22;">
  Address line 2: always visible (default), revealed by a text button (`toggle`), or never collected. Defaults to `"always"`.
</ResponseField>

<ResponseField name="mode" type="&#x22;billing&#x22; | &#x22;shipping&#x22;">
  Which autocomplete family the fields advertise to the browser: `billing` (default) or `shipping`. Defaults to `"billing"`.
</ResponseField>

<ResponseField name="scope" type="&#x22;full&#x22; | &#x22;minimal&#x22;">
  `full` (default) collects the country's complete address format; `minimal` collects the AVS floor of ADDRESS fields only — country plus postal code. The name row is governed by the `name` prop independently of scope, and a rendered name row is required (set `name: 'none'` for a pure country+postal collection). Note: the standalone element never widens to a payment method's own declared billing floor — a card confirm requires the cardholder name, country, and postal code, so beside a card method keep `name` enabled or pass it in the confirm's `billingDetails`. Defaults to `"full"`.
</ResponseField>

<ResponseField name="organization" type="&#x22;name&#x22; | &#x22;none&#x22; | &#x22;name_with_type&#x22;">
  The organization row: hidden (default), a name field, or a name field plus a business/individual type select. Defaults to `"none"`.
</ResponseField>

<ResponseField name="defaultValues" type="{ name?: string | undefined; address?: { name?: string | undefined; first_name?: string | undefined; last_name?: string | undefined; organization?: string | undefined; organization_type?: &#x22;business&#x22; | &#x22;individual&#x22; | undefined; line1?: string | undefined; line2?: string | undefined; city?: string | undefined; state?: string | undefined; postal_code?: string | undefined; country?: string | undefined; } | undefined; }">
  Seed values applied once before first paint (`address.country` is ISO2). Takes precedence over IP-country detection.
</ResponseField>

<ResponseField name="detectCountry" type="boolean">
  Default the country from the buyer's IP (resolved before first paint). Falls back to the controller's `countryHint`, then US. Defaults to `true`.
</ResponseField>

<ResponseField name="allowedCountries" type="string[]">
  Restrict the country select to these ISO2 codes. A single entry locks the country — the select stays openable and shows the one choice.
</ResponseField>

<ResponseField name="autocomplete" type="boolean">
  Google Places suggestions on the street-address field. When Places is unavailable (no key, blocked loader) the field is a plain input. Defaults to `true`.
</ResponseField>

<ResponseField name="customFields" type="({ key: string; label: string; type: &#x22;text&#x22; | &#x22;select&#x22; | &#x22;date&#x22; | &#x22;phone&#x22;; position: &#x22;after_name&#x22; | &#x22;after_organization&#x22; | &#x22;before_country&#x22; | &#x22;after_address&#x22;; required?: boolean | undefined; options?: string[] | undefined; format?: string | undefined; autocomplete?: string | undefined; })[]">
  Extra fields rendered inline with the same chrome: `{ key, label, type: text|select|date|phone, position: after_name|after_organization|before_country|after_address, required?, options?, format?, autocomplete? }`. Values are validated centrally and emitted under the separate `custom` bag.
</ResponseField>

<ResponseField name="countryHint" type="string">
  Optional ISO2 fallback for the country-detect chain (defaultValues > IP country > this > US) — e.g. derived from a checkout currency when it maps to exactly one country. Empty (default) = no hint. (When the payments controller later declares this element, its currency-derived hint wants to layer over this — the framework has no controller-OR-consumer prop source yet, so that wiring lands with that chunk.) Defaults to `""`.
</ResponseField>

## Events

Pass a callback in the create options (or React prop) to receive these.

### `onChange`

The address changed — `complete: true` means every required field for the selected country (plus any required custom fields) is filled and valid. `address` uses the confirmation-token billing\_details naming (`postal_code`, ISO2 `country`); custom field values ride the separate `custom` bag.

**Signature:** `((payload: { complete: boolean; address: { name?: string | undefined; first_name?: string | undefined; last_name?: string | undefined; organization?: string | undefined; organization_type?: "business" | "individual" | undefined; line1?: string | undefined; line2?: string | undefined; city?: string | undefined; state?: string | undefined; postal_code?: string | undefined; country: string; }; custom: Record<string, string>; }) => void)`

### `onLoaderStart`

Fired the moment the element's own loading skeleton has painted inside its frame — the earliest point a consumer-managed loading state can hand off without ever exposing a blank. Always precedes `onReady`; most consumers only need `onReady`.

**Signature:** `(() => void)`

### `onReady`

Fired once the element has booted and painted its first complete frame.

**Signature:** `(() => void)`

### `onError`

Fired when the element fails to load or crashes; the element shows its own error fallback. `message` is human-readable; framework refusals also carry `code` (e.g. `HOST_SOURCE_FAILED`, with `sourceKey` naming the failed hostState key) so hosts can switch on codes, never message text.

**Signature:** `((e: { message: string; code?: string | undefined; sourceKey?: string | undefined; }) => void)`

## Methods

Call these on the element handle — the return of `create` (vanilla) or the component `ref` (React).

### `validate`

Validate the whole form, revealing every error inline. Resolves `{ complete, address, errors }` — never throws; `errors` is empty exactly when `complete` is true. Error keys are the contract field keys (`postal_code`, `line1`, …), `custom:<key>` for custom fields, and the transient `form` key returned while the form is still loading.

**Signature:** `() => Promise<{ complete: boolean; address: { name?: string | undefined; first_name?: string | undefined; last_name?: string | undefined; organization?: string | undefined; organization_type?: "business" | "individual" | undefined; line1?: string | undefined; line2?: string | undefined; city?: string | undefined; state?: string | undefined; postal_code?: string | undefined; country: string; }; errors: Record<string, string>; }>`

### `getValues`

Read the current values without validating or revealing errors: `{ address, custom }`.

**Signature:** `() => Promise<{ address: { name?: string | undefined; first_name?: string | undefined; last_name?: string | undefined; organization?: string | undefined; organization_type?: "business" | "individual" | undefined; line1?: string | undefined; line2?: string | undefined; city?: string | undefined; state?: string | undefined; postal_code?: string | undefined; country: string; }; custom: Record<string, string>; }>`

### `mount`

Place the element on the page: appends its container to `target` (a CSS selector or an element) and starts loading. Nothing renders until this is called. React consumers never call it — the component mounts itself.

**Signature:** `(target: string | HTMLElement) => void`

### `destroy`

Remove the element from the page and release its frame and subscriptions. Safe to call more than once. React consumers never call it — unmounting the component does it.

**Signature:** `() => void`

### `update`

Change this element's consumer props after mount — it re-renders with the merged props. React consumers never call it — updating the JSX props does the same.

**Signature:** `(options: Partial<AddressElementProps>) => void`

## Styling

Each part below is a stable class name — safe to depend on. Restyle a part by mapping its class to a **style declaration object** under `appearance.classes` (properties camelCase or kebab-case, values as strings with units — the same shape as React's `style` prop). The element renders in its own frame, so page stylesheets can't reach it: these declarations are sanitized against a safe-property allowlist and injected inside the frame for you.

| Class                            | Targets                                                                                             |
| -------------------------------- | --------------------------------------------------------------------------------------------------- |
| `.whop-Address`                  | The address form root                                                                               |
| `.whop-AddressErrorSummary`      | The summary line shown when validation reveals missing or invalid fields                            |
| `.whop-AddressField`             | One field cell in the address form                                                                  |
| `.whop-AddressFieldError`        | The error line under an address field (full layout)                                                 |
| `.whop-AddressFieldInput`        | A text input in the address form                                                                    |
| `.whop-AddressFieldInputInvalid` | Added to an address input while it fails validation                                                 |
| `.whop-AddressFieldInvalid`      | Added to a compact field cell while it fails validation                                             |
| `.whop-AddressFieldLabel`        | The label above an address field (full layout)                                                      |
| `.whop-AddressFieldSelect`       | A select (country, state, organization type) in the address form                                    |
| `.whop-AddressLine2Toggle`       | The "Add address line 2" text button shown while line 2 is collapsed                                |
| `.whop-AddressManualEntry`       | The "Enter address manually" text button below the collapsed form — expands the full country format |
| `.whop-AddressSuggestion`        | One suggestion row in the autocomplete overlay                                                      |
| `.whop-AddressSuggestionActive`  | Added to the keyboard/pointer-active suggestion row                                                 |
| `.whop-AddressSuggestionManual`  | The "Enter address manually" row closing the suggestions list                                       |
| `.whop-AddressSuggestions`       | The autocomplete suggestions overlay anchored to the address line 1 field                           |

```ts theme={null}
const payments = whop.payments.create({
  appearance: {
    classes: {
      'whop-Address': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressErrorSummary': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressField': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressFieldError': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressFieldInput': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressFieldInputInvalid': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressFieldInvalid': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressFieldLabel': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressFieldSelect': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressLine2Toggle': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressManualEntry': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressSuggestion': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressSuggestionActive': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressSuggestionManual': { borderRadius: '8px', fontWeight: '600' },
      'whop-AddressSuggestions': { borderRadius: '8px', fontWeight: '600' }
    }
  }
});

// restyle live at any point — the same shape through update()
payments.update({
  appearance: { classes: { 'whop-Address': { fontWeight: '700' } } }
});
```

In React, pass the same object as the `appearance` prop on `<Payments>`; `appearance` also applies globally at `WhopElements({ appearance })`.
