# AddressInput

> Address form with cascading country, city and area comboboxes (searchable in English or Arabic), street and detail fields and an embedded PhoneInput. Places come from a pluggable LocationsDataSource, by default the CircleXO hub.

Source: https://docs.nasaqui.com/components/address-input

## Install

```bash
npx shadcn@latest add https://docs.nasaqui.com/r/address-input.json
```

One form for a postal address. Country, city and area are comboboxes that cascade: city stays disabled until a
country is chosen, area until a city is chosen, and choosing a new parent clears the children. Each list is
searchable by its English or Arabic name. Below them are street, building, floor, apartment, landmark and postal code
fields, and a [`PhoneInput`](https://docs.nasaqui.com/components/phone-input) whose value is E.164. The value is a plain snake_case object
(`Address`) that can be posted to an API as it is.

Places are loaded through a `LocationsDataSource`. The default is the CircleXO hub public locations API; pass your own
object to use another API or a static list. There is no map: `lat` and `lng` are part of the type and pass through
untouched, but the component never sets them.

## When to use

- Checkout, delivery, billing and profile forms in the Gulf and Arab world, where a place has an English and an Arabic name.
- Any form that must store country, city and area as ids from one reference list.

## When not to use

- A single country field: use [`CountrySelect`](https://docs.nasaqui.com/components/country-select).
- Free-text addresses with no reference data: use `Input` and `Textarea`.
- Picking a point on a map: Nasaq has no map component.

## Import

```tsx
import { AddressInput, createHubLocationsDataSource, type Address } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"
```

## Quick start

```tsx
import { AddressInput, type Address } from "@fadymondy/nasaq/web";
import { useState } from "react";

export function Delivery() {
  const [address, setAddress] = useState<Address>({ street: "" });
  return <AddressInput value={address} onValueChange={setAddress} />;
}
```

## Anatomy

```
AddressInput                    div                      data-slot="address-input"
├─ country                      Field + Combobox         data-slot="address-input-country"
├─ city                         Field + Combobox         data-slot="address-input-city"
├─ area                         Field + Combobox         data-slot="address-input-area"
├─ street                       Field + Input            data-slot="address-input-street"
├─ building, floor, apartment   Field + Input            data-slot="address-input-building" / -floor / -apartment
├─ postal code                  Field + Input (ltr)      data-slot="address-input-postal-code"
├─ landmark                     Field + Input            data-slot="address-input-landmark"
└─ phone                        Field + PhoneInput       data-slot="address-input-phone"   (showPhone)
```

## API

### `AddressInput`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value?` | `Address` | none | Controlled address. |
| `defaultValue?` | `Address` | `{ street: "" }` | Initial address when uncontrolled. |
| `onValueChange?` | `(value: Address) => void` | none | Called with the whole address on every change. Optional fields that are empty are left out. Changing the country drops `city_id` and `area_id`; changing the city drops `area_id`. |
| `dataSource?` | `LocationsDataSource` | `createHubLocationsDataSource()` | Where countries, cities and areas come from. Create it once (module scope or `useMemo`); a new object on each render reloads the lists. |
| `showPhone?` | `boolean` | `true` | Show the phone field. |
| `disabled?` | `boolean` | `false` | Disables every field. |
| `invalid?` | `boolean` | `false` | Sets `aria-invalid` on the comboboxes, street and phone. |
| `labels?` | `Partial<AddressInputLabels>` | built-in EN / AR | Override any string: `country`, `city`, `area`, `street`, `building`, `floor`, `apartment`, `landmark`, `postalCode`, `phone`, `selectCountry`, `selectCity`, `selectArea`, `empty`, `loading`, `loadError`, `clear`, `open`. |
| `locale?` / `dir?` | `string` / `"ltr" \| "rtl"` | from the provider | Override for strings, place names and direction. |
| `className?` | `string` | none | Merged onto the root grid. |

### `Address`

```ts
interface Address {
  country_id?: number;
  city_id?: number;
  area_id?: number;
  street: string;
  building?: string;
  floor?: string;
  apartment?: string;
  landmark?: string;
  postal_code?: string;
  lat?: number;   // passed through, never set by the component
  lng?: number;
  phone?: string; // E.164
}
```

### `LocationsDataSource`

| Member | Signature | Description |
| --- | --- | --- |
| `countries` | `() => Promise<LocationCountry[]>` | All countries. |
| `cities` | `(countryId: number) => Promise<LocationCity[]>` | Cities of a country. |
| `areas` | `(cityId: number) => Promise<LocationArea[]>` | Areas of a city. Filtered in the browser, so keep it to one city. |
| `search?` | `(q: string, options: { type: "country" \| "city" \| "area"; countryId?: number; cityId?: number; limit?: number }) => Promise<LocationItem[]>` | Optional server-side search. The built-in inputs do not call it. |

`LocationCountry` is `{ id, iso2, iso3?, name_en, name_ar, phone_code?, emoji?, region?, lat?, lng?, currency_code? }`,
`LocationCity` is `{ id, country_id, name_en, name_ar, lat?, lng?, timezone? }`, `LocationArea` is
`{ id, city_id, name_en, name_ar }`. `name_en` or `name_ar` may be an empty string; the UI shows the other one.

### `createHubLocationsDataSource({ baseUrl?, fetch? })`

Returns a `LocationsDataSource` for the CircleXO hub REST API (public, no auth):
`GET {base}/api/locations/countries`, `/cities?country_id=`, `/areas?city_id=`, `/search?q=&type=&country_id=&city_id=&limit=`,
each returning `{ "items": [...] }`. Responses are cached in memory per source object; a failed request is not cached.

| Option | Type | Default | Description |
| --- | --- | --- | --- |
| `baseUrl?` | `string` | `DEFAULT_HUB_URL` (`https://app.circlexo.com`) | Hub origin, without a trailing path. |
| `fetch?` | `typeof fetch` | `globalThis.fetch` | Custom fetch, for tests or server use. |

### Helpers

| Export | Description |
| --- | --- |
| `placeName(item, lang)` | `item.name_en` or `item.name_ar` for `lang`, falling back to the other when empty. |
| `DEFAULT_HUB_URL` | The default hub origin. |

## Examples

### Own data source

```tsx
import { AddressInput, type LocationsDataSource } from "@fadymondy/nasaq/web";

const source: LocationsDataSource = {
  countries: async () => [{ id: 1, iso2: "SA", name_en: "Saudi Arabia", name_ar: "السعودية" }],
  cities: async () => [{ id: 10, country_id: 1, name_en: "Riyadh", name_ar: "الرياض" }],
  areas: async () => [{ id: 100, city_id: 10, name_en: "Olaya", name_ar: "العليا" }],
};

export const Static = () => <AddressInput dataSource={source} />;
```

### Another hub, no phone

```tsx
import { AddressInput, createHubLocationsDataSource } from "@fadymondy/nasaq/web";

const staging = createHubLocationsDataSource({ baseUrl: "https://staging.example.com" });

export const Shipping = () => <AddressInput dataSource={staging} showPhone={false} />;
```

### Arabic

```tsx
import { AddressInput, NasaqProvider } from "@fadymondy/nasaq/web";

export const AddressAr = () => (
  <NasaqProvider locale="ar" target="scope">
    <AddressInput />
  </NasaqProvider>
);
```

## Accessibility

Every field has a visible `FieldLabel`. The comboboxes are Base UI comboboxes; the phone field's own country list is
named "Country" by `PhoneInput`. A disabled city or area is a real `disabled` input, so it leaves the tab order.
The empty message of a list reads "Loading...", "Could not load the list." or "No results." as appropriate.

| Key | Action |
| --- | --- |
| `Down` / typing in a combobox | Opens the list and filters it by English or Arabic name. |
| `Up` / `Down` | Moves the highlighted item. |
| `Enter` | Selects it; the children are cleared and the next list loads. |
| `Esc` | Closes the list. |

Caller must localise any `labels` override. Built-in strings come in English and Arabic.

## RTL & i18n

- The grid follows `dir`: in Arabic the first column is at the right.
- Names follow the active language and fall back to the other one when empty (Egyptian cities are Arabic only). Search matches both, folding Arabic letter variants.
- The postal code and phone fields are left to right in every direction.

## Styling & tokens

- Fields use the same tokens as `Input` and `Combobox`: `border-input`, `bg-card`, `rounded-control`, focus `nq-focus`, invalid `nq-danger`.
- Slots: `address-input` and the `address-input-*` slots in Anatomy. `data-invalid` is set on the root when `invalid`.
- Extend with `className`; the root is `grid sm:grid-cols-2`, so `className="sm:grid-cols-1"` makes a single column. Never override colours with raw hex.

## Do / Don't

- **Do** create the data source once and reuse it so lists are cached.
- **Do** validate `street` (required) and the ids on the server.
- **Don't** expect a map pin; set `lat` and `lng` yourself if you have them.
- **Don't** point `dataSource` at an endpoint that returns thousands of areas per city; filtering is client-side.

## Related

- [PhoneInput](https://docs.nasaqui.com/components/phone-input) · [CountrySelect](https://docs.nasaqui.com/components/country-select) · [Combobox](https://docs.nasaqui.com/components/combobox) · [Field](https://docs.nasaqui.com/components/field) · [CountryFlag](https://docs.nasaqui.com/components/country-flag)

## Lab

https://nasaq-ui.fadymondy.com/?path=/docs/components-forms-address-input--docs

## Code

### React

```tsx
import { AddressInput, type Address } from "@fadymondy/nasaq/web";
import { useState } from "react";

export function Delivery() {
  const [address, setAddress] = useState<Address>({ street: "" });
  return <AddressInput value={address} onValueChange={setAddress} />;
}
```

### shadcn

```tsx
import { AddressInput, type Address } from "@/components/ui/address-input";
import { useState } from "react";

export function Delivery() {
  const [address, setAddress] = useState<Address>({ street: "" });
  return <AddressInput value={address} onValueChange={setAddress} />;
}
```

### Vue

```vue
<script setup lang="ts">
import { NqAddressInput, type Address, type LocationsDataSource } from "@fadymondy/nasaq/vue";
import { ref } from "vue";

// A small offline source so the example does not depend on the network. Leave `data-source` out to use the CircleXO hub.
const source: LocationsDataSource = {
  countries: async () => [
    { id: 65, iso2: "EG", name_en: "Egypt", name_ar: "مصر" },
    { id: 187, iso2: "SA", name_en: "Saudi Arabia", name_ar: "السعودية" },
  ],
  cities: async (countryId) =>
    countryId === 65
      ? [{ id: 2, country_id: 65, name_en: "Alexandria", name_ar: "الإسكندرية" }]
      : [{ id: 10, country_id: 187, name_en: "Riyadh", name_ar: "الرياض" }],
  areas: async (cityId) => [{ id: cityId * 100 + 1, city_id: cityId, name_en: "Downtown", name_ar: "وسط المدينة" }],
};

const address = ref<Address>({ street: "" });
</script>

<template>
  <div class="w-[34rem] max-w-full">
    <NqAddressInput v-model="address" :data-source="source" />
  </div>
</template>
```

### Blade

```blade
<div class="w-full max-w-xl">
    <x-nq::address-input :value="['street' => '']" />
</div>
```

### HTML + Alpine

```html
<div class="w-full max-w-xl">
    <div data-slot="address-input" dir="ltr" lang="en" x-data="nqAddressInput(JSON.parse('{\u0022street\u0022:\u0022\u0022}'), JSON.parse('{\u0022locale\u0022:\u0022en\u0022,\u0022hub\u0022:true}'))" x-modelable="address"
        class="grid gap-3 sm:grid-cols-2">
            <div data-slot="address-input-country" :data-disabled="placeDisabled('country') ? '' : null" class="group/field flex flex-col gap-1.5">
            <label data-slot="field-label" for="nq-address-000001-country" class="text-label text-foreground group-data-disabled/field:opacity-50">Country</label>
            <div x-data="nqPlaceSelect({ options: () => placeOptions('country'), value: () => address.country_id, set: (v) => setPlace('country', v), disabled: () => placeDisabled('country'), empty: () => placeEmpty('country') })" class="contents">
                <div data-slot="combobox-input-group" x-ref="anchor"
    class="flex min-h-control min-w-0 w-full items-center gap-1 rounded-control border border-input bg-card text-body text-foreground transition-colors duration-150 ease-nq focus-within:border-nq-focus focus-within:outline-1 focus-within:outline-nq-focus has-[[data-invalid]]:border-nq-danger has-[[aria-invalid=true]]:border-nq-danger has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50 h-control ps-3 pe-1.5">
    <input data-slot="combobox-input" x-ref="input" x-bind="input"
                id="nq-address-000001-country" placeholder="Select a country" class="h-full min-w-0 flex-1 border-0 bg-transparent text-body text-foreground outline-none placeholder:text-muted-foreground pointer-coarse:text-[16px]">
            <button data-slot="combobox-clear" x-bind="clear" aria-label="Clear"
            class="flex size-6 shrink-0 cursor-default items-center justify-center rounded-control text-muted-foreground outline-none hover:text-foreground focus-visible:outline-1 focus-visible:outline-nq-focus [&_svg]:size-4 data-[hidden]:hidden"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M18 6 6 18"/>
  <path d="m6 6 12 12"/>
</svg></button>
        <button data-slot="combobox-trigger" x-bind="trigger" aria-label="Open"
        class="flex size-6 shrink-0 cursor-default items-center justify-center rounded-control text-muted-foreground outline-none hover:text-foreground focus-visible:outline-1 focus-visible:outline-nq-focus [&_svg]:size-4"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m7 15 5 5 5-5"/>
  <path d="m7 9 5-5 5 5"/>
</svg></button>
</div>
                <template x-teleport="body">
    <div data-slot="combobox-content" x-ref="popup" x-bind="popup" x-nq-presence="open" x-anchor.bottom-start.offset.4="$refs.anchor"
        class="z-50 w-[var(--anchor-width)] max-h-[min(var(--available-height),20rem)] overflow-y-auto rounded-floating border border-border bg-popover p-1.5 text-popover-foreground shadow-floating outline-none transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
        <div data-slot="combobox-empty" x-bind="emptyState" class="px-2.5 py-2 text-body-sm text-muted-foreground empty:hidden"></div>
                    <div data-slot="combobox-list" class="outline-none">
                        <template x-if="open"><div class="contents"><template x-for="o in matches()" :key="o.value">
                            <div data-slot="combobox-item" x-bind="item(o)"
                                class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
                                <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
                                    <span x-show="String(cfg.value()) === String(o.value)" x-cloak class="contents"><svg class="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg></span>
                                </span>
                                <span data-slot="combobox-item-text" class="min-w-0 flex-1 truncate">
                                                                            <span class="flex items-center gap-2">
                                            <span data-slot="country-flag" aria-hidden="true" x-data="nqCountryFlag(o.iso || '')" x-html="svg"
                                                class="relative inline-block aspect-[3/2] h-[1em] shrink-0 overflow-hidden rounded-[2px] bg-muted align-[-0.125em] text-[1rem] [&>svg]:block [&>svg]:size-full after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:ring-1 after:ring-foreground/15 after:ring-inset"></span>
                                            <span class="min-w-0 flex-1 truncate" x-text="o.label"></span>
                                        </span>
                                                                    </span>
                            </div>
                        </template></div></template>
                    </div>
    </div>
</template>
            </div>
        </div>
            <div data-slot="address-input-city" :data-disabled="placeDisabled('city') ? '' : null" class="group/field flex flex-col gap-1.5">
            <label data-slot="field-label" for="nq-address-000001-city" class="text-label text-foreground group-data-disabled/field:opacity-50">City</label>
            <div x-data="nqPlaceSelect({ options: () => placeOptions('city'), value: () => address.city_id, set: (v) => setPlace('city', v), disabled: () => placeDisabled('city'), empty: () => placeEmpty('city') })" class="contents">
                <div data-slot="combobox-input-group" x-ref="anchor"
    class="flex min-h-control min-w-0 w-full items-center gap-1 rounded-control border border-input bg-card text-body text-foreground transition-colors duration-150 ease-nq focus-within:border-nq-focus focus-within:outline-1 focus-within:outline-nq-focus has-[[data-invalid]]:border-nq-danger has-[[aria-invalid=true]]:border-nq-danger has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50 h-control ps-3 pe-1.5">
    <input data-slot="combobox-input" x-ref="input" x-bind="input"
                id="nq-address-000001-city" placeholder="Select a city" class="h-full min-w-0 flex-1 border-0 bg-transparent text-body text-foreground outline-none placeholder:text-muted-foreground pointer-coarse:text-[16px]">
            <button data-slot="combobox-clear" x-bind="clear" aria-label="Clear"
            class="flex size-6 shrink-0 cursor-default items-center justify-center rounded-control text-muted-foreground outline-none hover:text-foreground focus-visible:outline-1 focus-visible:outline-nq-focus [&_svg]:size-4 data-[hidden]:hidden"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M18 6 6 18"/>
  <path d="m6 6 12 12"/>
</svg></button>
        <button data-slot="combobox-trigger" x-bind="trigger" aria-label="Open"
        class="flex size-6 shrink-0 cursor-default items-center justify-center rounded-control text-muted-foreground outline-none hover:text-foreground focus-visible:outline-1 focus-visible:outline-nq-focus [&_svg]:size-4"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m7 15 5 5 5-5"/>
  <path d="m7 9 5-5 5 5"/>
</svg></button>
</div>
                <template x-teleport="body">
    <div data-slot="combobox-content" x-ref="popup" x-bind="popup" x-nq-presence="open" x-anchor.bottom-start.offset.4="$refs.anchor"
        class="z-50 w-[var(--anchor-width)] max-h-[min(var(--available-height),20rem)] overflow-y-auto rounded-floating border border-border bg-popover p-1.5 text-popover-foreground shadow-floating outline-none transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
        <div data-slot="combobox-empty" x-bind="emptyState" class="px-2.5 py-2 text-body-sm text-muted-foreground empty:hidden"></div>
                    <div data-slot="combobox-list" class="outline-none">
                        <template x-if="open"><div class="contents"><template x-for="o in matches()" :key="o.value">
                            <div data-slot="combobox-item" x-bind="item(o)"
                                class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
                                <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
                                    <span x-show="String(cfg.value()) === String(o.value)" x-cloak class="contents"><svg class="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg></span>
                                </span>
                                <span data-slot="combobox-item-text" class="min-w-0 flex-1 truncate">
                                                                            <span x-text="o.label"></span>
                                                                    </span>
                            </div>
                        </template></div></template>
                    </div>
    </div>
</template>
            </div>
        </div>
            <div data-slot="address-input-area" :data-disabled="placeDisabled('area') ? '' : null" class="group/field flex flex-col gap-1.5">
            <label data-slot="field-label" for="nq-address-000001-area" class="text-label text-foreground group-data-disabled/field:opacity-50">Area</label>
            <div x-data="nqPlaceSelect({ options: () => placeOptions('area'), value: () => address.area_id, set: (v) => setPlace('area', v), disabled: () => placeDisabled('area'), empty: () => placeEmpty('area') })" class="contents">
                <div data-slot="combobox-input-group" x-ref="anchor"
    class="flex min-h-control min-w-0 w-full items-center gap-1 rounded-control border border-input bg-card text-body text-foreground transition-colors duration-150 ease-nq focus-within:border-nq-focus focus-within:outline-1 focus-within:outline-nq-focus has-[[data-invalid]]:border-nq-danger has-[[aria-invalid=true]]:border-nq-danger has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50 h-control ps-3 pe-1.5">
    <input data-slot="combobox-input" x-ref="input" x-bind="input"
                id="nq-address-000001-area" placeholder="Select an area" class="h-full min-w-0 flex-1 border-0 bg-transparent text-body text-foreground outline-none placeholder:text-muted-foreground pointer-coarse:text-[16px]">
            <button data-slot="combobox-clear" x-bind="clear" aria-label="Clear"
            class="flex size-6 shrink-0 cursor-default items-center justify-center rounded-control text-muted-foreground outline-none hover:text-foreground focus-visible:outline-1 focus-visible:outline-nq-focus [&_svg]:size-4 data-[hidden]:hidden"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M18 6 6 18"/>
  <path d="m6 6 12 12"/>
</svg></button>
        <button data-slot="combobox-trigger" x-bind="trigger" aria-label="Open"
        class="flex size-6 shrink-0 cursor-default items-center justify-center rounded-control text-muted-foreground outline-none hover:text-foreground focus-visible:outline-1 focus-visible:outline-nq-focus [&_svg]:size-4"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m7 15 5 5 5-5"/>
  <path d="m7 9 5-5 5 5"/>
</svg></button>
</div>
                <template x-teleport="body">
    <div data-slot="combobox-content" x-ref="popup" x-bind="popup" x-nq-presence="open" x-anchor.bottom-start.offset.4="$refs.anchor"
        class="z-50 w-[var(--anchor-width)] max-h-[min(var(--available-height),20rem)] overflow-y-auto rounded-floating border border-border bg-popover p-1.5 text-popover-foreground shadow-floating outline-none transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
        <div data-slot="combobox-empty" x-bind="emptyState" class="px-2.5 py-2 text-body-sm text-muted-foreground empty:hidden"></div>
                    <div data-slot="combobox-list" class="outline-none">
                        <template x-if="open"><div class="contents"><template x-for="o in matches()" :key="o.value">
                            <div data-slot="combobox-item" x-bind="item(o)"
                                class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected data-disabled:pointer-events-none data-disabled:opacity-50">
                                <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
                                    <span x-show="String(cfg.value()) === String(o.value)" x-cloak class="contents"><svg class="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg></span>
                                </span>
                                <span data-slot="combobox-item-text" class="min-w-0 flex-1 truncate">
                                                                            <span x-text="o.label"></span>
                                                                    </span>
                            </div>
                        </template></div></template>
                    </div>
    </div>
</template>
            </div>
        </div>
        <div data-slot="address-input-street" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     class="flex flex-col gap-1.5 sm:col-span-2">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Street</label>
        <input data-slot="input" type="text"
                    x-model="address.street" autocomplete="address-line1" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control">
</div>
            <div data-slot="address-input-building" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     class="flex flex-col gap-1.5">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Building</label>
            <input data-slot="input" type="text"
                    x-model="address.building" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control">
</div>
            <div data-slot="address-input-floor" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     class="flex flex-col gap-1.5">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Floor</label>
            <input data-slot="input" type="text"
                    x-model="address.floor" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control">
</div>
            <div data-slot="address-input-apartment" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     class="flex flex-col gap-1.5">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Apartment</label>
            <input data-slot="input" type="text"
                    x-model="address.apartment" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control">
</div>
            <div data-slot="address-input-postal-code" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     class="flex flex-col gap-1.5">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Postal code</label>
            <input data-slot="input" type="text"
     dir="ltr"                 x-model="address.postal_code" autocomplete="postal-code" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control text-start">
</div>
        <div class="sm:col-span-2">
        <div data-slot="address-input-landmark" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     class="flex flex-col gap-1.5">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Landmark</label>
            <input data-slot="input" type="text"
                    x-model="address.landmark" class="w-full min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control">
</div>
    </div>
            <div data-slot="address-input-phone" x-data="nqField(false)" x-modelable="invalid" x-id="['nq-field']"
         data-valid     class="flex flex-col gap-1.5 sm:col-span-2">
    <label data-slot="field-label"  class="text-label text-foreground data-disabled:opacity-50">Phone</label>
            <div data-slot="phone-input-root" x-data="nqPhoneInput('', JSON.parse('{\u0022defaultCountry\u0022:\u0022SA\u0022,\u0022locale\u0022:\u0022en\u0022}'))" x-modelable="value" x-id="['nq-phone']"
    x-model="address.phone" class="block w-full min-w-0">
    <div role="group" data-slot="phone-input" x-ref="anchor"         class="group/input-group flex h-control min-h-[var(--nq-touch-min,0px)] w-full min-w-0 items-center overflow-hidden rounded-control border border-input bg-card text-body text-foreground transition-colors duration-150 ease-nq focus-within:border-nq-focus focus-within:outline-1 focus-within:outline-nq-focus has-[[data-invalid]]:border-nq-danger has-[[aria-invalid=true]]:border-nq-danger has-[input:disabled]:cursor-not-allowed has-[input:disabled]:opacity-50">
        <button data-slot="phone-input-country" x-ref="trigger" x-bind="trigger"             class="order-first flex h-full shrink-0 cursor-default items-center gap-1.5 border-e border-input ps-3 pe-2 text-body-sm text-foreground outline-none transition-colors duration-150 ease-nq hover:bg-nq-hover focus-visible:bg-nq-hover data-[state=open]:bg-nq-hover disabled:cursor-not-allowed">
            <span data-slot="country-flag" aria-hidden="true" x-html="flag"
                class="relative inline-block aspect-[3/2] h-[1em] shrink-0 overflow-hidden rounded-[2px] bg-muted align-[-0.125em] text-[1.125rem] [&>svg]:block [&>svg]:size-full after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:ring-1 after:ring-foreground/15 after:ring-inset"></span>
            <bdi dir="ltr" class="tabular-nums" x-text="'+' + country().dial">+966</bdi>
            <svg aria-hidden="true" class="size-3.5 text-muted-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m7 15 5 5 5-5"/>
  <path d="m7 9 5-5 5 5"/>
</svg>        </button>
        <input data-slot="input-group-input" dir="ltr" x-bind="field"              aria-label="Phone" class="h-full min-w-0 flex-1 border-0 bg-transparent px-3 text-body text-foreground outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed pointer-coarse:text-[16px] text-start tabular-nums">
            </div>
    <template x-teleport="body">
        <div data-slot="phone-input-content" x-ref="popup" x-bind="popup" x-nq-presence="open" x-anchor.bottom-start.offset.4="$refs.anchor" :dir="lang === 'ar' ? 'rtl' : 'ltr'"
            class="z-50 w-[max(var(--anchor-width),18rem)] overflow-hidden rounded-floating border border-border bg-popover text-popover-foreground shadow-floating outline-none transition-opacity duration-150 ease-nq data-starting-style:opacity-0 data-ending-style:opacity-0">
            <div class="border-b border-border p-1.5">
                <input data-slot="phone-input-search" x-ref="search" x-bind="search"
                    class="h-control-sm w-full min-w-0 rounded-control border-0 bg-transparent px-2 text-body text-foreground outline-none placeholder:text-muted-foreground pointer-coarse:text-[16px]">
            </div>
            <div class="max-h-64 overflow-y-auto p-1.5">
                <template x-if="open"><div class="contents"><template x-for="c in matches()" :key="c.iso">
                    <div data-slot="combobox-item" x-bind="item(c)"
                        class="relative flex h-nav-row min-h-[var(--nq-touch-min,0px)] cursor-default select-none items-center gap-2.5 rounded-control ps-8 pe-2.5 text-body-sm text-foreground outline-none data-highlighted:bg-nq-selected">
                        <span aria-hidden="true" class="absolute start-2.5 inline-flex size-4 items-center justify-center">
                            <span x-show="c.iso === iso" x-cloak class="contents"><svg class="size-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg></span>
                        </span>
                        <span class="flex min-w-0 flex-1 items-center gap-2">
                            <span data-slot="country-flag" aria-hidden="true" x-data="nqCountryFlag(c.iso)" x-html="svg"
                                class="relative inline-block aspect-[3/2] h-[1em] shrink-0 overflow-hidden rounded-[2px] bg-muted align-[-0.125em] text-[1rem] [&>svg]:block [&>svg]:size-full after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:ring-1 after:ring-foreground/15 after:ring-inset"></span>
                            <span class="min-w-0 flex-1 truncate" x-text="c.label"></span>
                            <bdi dir="ltr" class="shrink-0 text-muted-foreground tabular-nums" x-text="'+' + c.dial"></bdi>
                        </span>
                    </div>
                </template></div></template>
                <div x-bind="emptyState" class="px-2.5 py-2 text-body-sm text-muted-foreground">No country found.</div>
            </div>
        </div>
    </template>
</div>
</div>
    </div>
</div>
```
