# RelationPicker

> A field that points at another record and finds it by searching your API, storing ids and showing names, for one record or many, with create from typed text and loading, empty and error states.

Source: https://docs.nasaqui.com/components/relation-picker

## Install

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

A foreign-key field. The value is an id; the person sees a name. Results come from your `search` function, so the list
can be as long as your table. It is built on [Combobox](https://docs.nasaqui.com/components/combobox), so filtering is Arabic-aware when you
pass fixed `options` instead.

## When to use

- Choosing a customer, project, owner or parent from a table too big for a Select.

## When not to use

- Fewer than about 20 choices: a [Select](https://docs.nasaqui.com/components/select).
- Free tags: a tags input.

## Import

```tsx
import { RelationPicker } from "@fadymondy/nasaq/web";
```

## Quick start

```tsx
<RelationPicker
  aria-label="Customer"
  value={customerId}
  onValueChange={setCustomerId}
  search={(query, signal) => fetch(`/api/customers?q=${query}`, { signal }).then((r) => r.json())}
  resolve={(ids) => fetch(`/api/customers?ids=${ids.join(",")}`).then((r) => r.json())}
  onCreate={async (name) => ({ value: await api.createCustomer(name), label: name })}
/>
```

Add `multiple` and pass `string[]` for several records.

## Anatomy

```
RelationPicker            data-slot="relation-picker"
└─ Combobox               input (single) or chips (multiple)
   └─ list                results, the selected records, and a "Create ..." row
```

## API

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` / `defaultValue` / `onValueChange` | `string \| null`, or `string[]` with `multiple` | none | Ids. The callback also gets the record or records. |
| `multiple` | `boolean` | `false` | Chips. |
| `search` | `(query, signal) => Promise<RelationOption[]>` | none | Called with an empty query when the list opens, then after `debounce`. Earlier calls are aborted. |
| `options` | `RelationOption[]` | none | Fixed records, searched on the client when `search` is omitted. |
| `resolve` | `(ids) => Promise<RelationOption[]>` | none | Names for saved ids the picker has not seen. |
| `onCreate` | `(query) => Promise<RelationOption \| { error }>` | none | Adds a row to create a record from the typed text. |
| `debounce` | `number` | `250` | Milliseconds. |
| `renderOption` | `(option) => ReactNode` | label and description | |
| `invalid`, `disabled`, `id`, `name`, `placeholder`, `aria-label` | | | `name` writes hidden inputs for a native form. |
| `locale`, `labels`, `className` | | | |

`RelationOption`: `value`, `label`, `labelAr`, `description`, `disabled`.

## Accessibility

- It is a combobox: type to search, arrow keys move, Enter picks, Escape closes.
- Loading, empty and error states are announced in a status region; the error has a retry button.
- Chips have a remove button named "Remove".

## RTL & i18n

Names use `labelAr` when the locale is Arabic. Labels and option text are isolated with `bdi dir="auto"`.

## Styling & tokens

Uses Combobox tokens. Extend with `className`.

## Do / Don't

- Do return a stable `value` (the id), never the label.
- Do provide `resolve` when the form loads saved values.
- Do not fetch in `renderOption`.

## Related

- [Combobox](https://docs.nasaqui.com/components/combobox)
- [SchemaForm](https://docs.nasaqui.com/components/schema-form)

## Lab

https://docs.nasaqui.com/?path=/docs/components-forms-relation-picker--docs

## Code

### React

```tsx
<RelationPicker
  aria-label="Customer"
  value={customerId}
  onValueChange={setCustomerId}
  search={(query, signal) => fetch(`/api/customers?q=${query}`, { signal }).then((r) => r.json())}
  resolve={(ids) => fetch(`/api/customers?ids=${ids.join(",")}`).then((r) => r.json())}
  onCreate={async (name) => ({ value: await api.createCustomer(name), label: name })}
/>
```

### shadcn

```tsx
<RelationPicker
  aria-label="Customer"
  value={customerId}
  onValueChange={setCustomerId}
  search={(query, signal) => fetch(`/api/customers?q=${query}`, { signal }).then((r) => r.json())}
  resolve={(ids) => fetch(`/api/customers?ids=${ids.join(",")}`).then((r) => r.json())}
  onCreate={async (name) => ({ value: await api.createCustomer(name), label: name })}
/>
```

### Vue

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

const customers: RelationOption[] = [
  { value: "c1", label: "Acme Trading", description: "billing@acme.example" },
  { value: "c2", label: "Nile Logistics", description: "ops@nile.example" },
  { value: "c3", label: "Riyadh Foods", labelAr: "أغذية الرياض", description: "hello@riyadh.example" },
];
const customerId = ref<string | null>("c2");

// In a real app these call your API: fetch(`/api/customers?q=${query}`, { signal }).
const search = (query: string, signal: AbortSignal) =>
  new Promise<RelationOption[]>((resolve, reject) => {
    const timer = setTimeout(() => resolve(customers.filter((c) => c.label.toLowerCase().includes(query.toLowerCase()))), 200);
    signal.addEventListener("abort", () => {
      clearTimeout(timer);
      reject(new DOMException("Aborted", "AbortError"));
    });
  });
const resolveIds = async (ids: readonly string[]) => customers.filter((c) => ids.includes(c.value));
const create = async (name: string): Promise<RelationOption> => ({ value: `new-${name}`, label: name });
</script>

<template>
  <div class="w-80">
    <NqRelationPicker v-model="customerId" aria-label="Customer" :search="search" :resolve="resolveIds" :on-create="create" />
  </div>
</template>
```

### Blade

```blade
@php
    $customers = [
        ['value' => 'c1', 'label' => 'Acme Trading', 'description' => 'billing@acme.example'],
        ['value' => 'c2', 'label' => 'Nile Logistics', 'description' => 'ops@nile.example'],
        ['value' => 'c3', 'label' => 'Riyadh Foods', 'labelAr' => 'أغذية الرياض', 'description' => 'hello@riyadh.example'],
    ];
@endphp
<div class="flex w-80 flex-col gap-6">
    <x-nq::relation-picker name="customer_id" value="c2" label="Customer" :options="$customers" />
    <x-nq::relation-picker name="remote_id" label="Remote customer" search-url="/api/customers" resolve-url="/api/customers" create-url="/api/customers" :debounce="50" />
    <x-nq::relation-picker name="team_ids" label="Team" :multiple="true" :value="['c1', 'c3']" :options="$customers" />
</div>
```

### HTML + Alpine

```html
<div class="flex w-80 flex-col gap-6">
    <div data-slot="relation-picker" x-data="nqRelationPicker(JSON.parse('{\u0022value\u0022:\u0022c2\u0022,\u0022multiple\u0022:false,\u0022options\u0022:[{\u0022value\u0022:\u0022c1\u0022,\u0022label\u0022:\u0022Acme Trading\u0022,\u0022description\u0022:\u0022billing@acme.example\u0022},{\u0022value\u0022:\u0022c2\u0022,\u0022label\u0022:\u0022Nile Logistics\u0022,\u0022description\u0022:\u0022ops@nile.example\u0022},{\u0022value\u0022:\u0022c3\u0022,\u0022label\u0022:\u0022Riyadh Foods\u0022,\u0022labelAr\u0022:\u0022\\u0623\\u063a\\u0630\\u064a\\u0629 \\u0627\\u0644\\u0631\\u064a\\u0627\\u0636\u0022,\u0022description\u0022:\u0022hello@riyadh.example\u0022}],\u0022searchUrl\u0022:null,\u0022resolveUrl\u0022:null,\u0022createUrl\u0022:null,\u0022debounce\u0022:250,\u0022ar\u0022:false,\u0022t\u0022:{\u0022empty\u0022:\u0022No results\u0022,\u0022hint\u0022:\u0022Type to search\u0022,\u0022searching\u0022:\u0022Searching\\u2026\u0022,\u0022error\u0022:\u0022Could not load results.\u0022,\u0022create\u0022:\u0022Create \\u201c{q}\\u201d\u0022,\u0022createFailed\u0022:\u0022Could not create it.\u0022}}'))" x-modelable="value" x-id="['nq-relation']"
    x-bind:data-busy="status === 'loading' || createState === 'busy' ? '' : undefined" class="min-w-0">
            <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" placeholder="Search…" aria-label="Customer"
                                                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 list"
                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">
                <span class="flex items-center justify-center gap-2" role="status">
                    <span x-show="status === 'loading'" x-cloak class="contents"><svg aria-hidden="true" class="size-4 animate-spin" 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="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg></span>
                    <span x-show="status === 'error'" x-cloak class="contents"><svg aria-hidden="true" class="size-4 text-nq-danger-text" 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="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/>
  <path d="M12 9v4"/>
  <path d="M12 17h.01"/>
</svg></span>
                    <span x-text="emptyText()"></span>
                    <button type="button" x-show="status === 'error'" x-cloak x-on:click="refresh(true)" class="text-foreground underline underline-offset-2">Try again</button>
                </span>
            </div>
            <template x-for="o in rows()" :key="o.value">
                <div data-slot="combobox-item" x-bind="row(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="isSelected(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">
                        <template x-if="isCreate(o)">
                            <span class="flex items-center gap-2 text-foreground"><svg aria-hidden="true" class="size-4 shrink-0" 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="M5 12h14"/>
  <path d="M12 5v14"/>
</svg><bdi dir="auto" class="truncate" x-text="o.label"></bdi></span>
                        </template>
                        <template x-if="!isCreate(o)">
                            <span class="flex min-w-0 flex-col leading-tight">
                                <bdi dir="auto" class="truncate" x-text="text(o)"></bdi>
                                <bdi x-show="o.description" dir="auto" class="truncate text-caption text-muted-foreground" x-text="o.description"></bdi>
                            </span>
                        </template>
                    </span>
                </div>
            </template>
        </div>
    </template>
    <p x-show="createState === 'failed'" x-cloak role="alert" class="mt-1.5 text-caption text-nq-danger-text">Could not create it.</p>
                        <input type="hidden" name="customer_id" :value="value ?? ''">
            </div>
    <div data-slot="relation-picker" x-data="nqRelationPicker(JSON.parse('{\u0022value\u0022:null,\u0022multiple\u0022:false,\u0022options\u0022:[],\u0022searchUrl\u0022:\u0022\\\/api\\\/customers\u0022,\u0022resolveUrl\u0022:\u0022\\\/api\\\/customers\u0022,\u0022createUrl\u0022:\u0022\\\/api\\\/customers\u0022,\u0022debounce\u0022:50,\u0022ar\u0022:false,\u0022t\u0022:{\u0022empty\u0022:\u0022No results\u0022,\u0022hint\u0022:\u0022Type to search\u0022,\u0022searching\u0022:\u0022Searching\\u2026\u0022,\u0022error\u0022:\u0022Could not load results.\u0022,\u0022create\u0022:\u0022Create \\u201c{q}\\u201d\u0022,\u0022createFailed\u0022:\u0022Could not create it.\u0022}}'))" x-modelable="value" x-id="['nq-relation']"
    x-bind:data-busy="status === 'loading' || createState === 'busy' ? '' : undefined" class="min-w-0">
            <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" placeholder="Search…" aria-label="Remote customer"
                                                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 list"
                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">
                <span class="flex items-center justify-center gap-2" role="status">
                    <span x-show="status === 'loading'" x-cloak class="contents"><svg aria-hidden="true" class="size-4 animate-spin" 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="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg></span>
                    <span x-show="status === 'error'" x-cloak class="contents"><svg aria-hidden="true" class="size-4 text-nq-danger-text" 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="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/>
  <path d="M12 9v4"/>
  <path d="M12 17h.01"/>
</svg></span>
                    <span x-text="emptyText()"></span>
                    <button type="button" x-show="status === 'error'" x-cloak x-on:click="refresh(true)" class="text-foreground underline underline-offset-2">Try again</button>
                </span>
            </div>
            <template x-for="o in rows()" :key="o.value">
                <div data-slot="combobox-item" x-bind="row(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="isSelected(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">
                        <template x-if="isCreate(o)">
                            <span class="flex items-center gap-2 text-foreground"><svg aria-hidden="true" class="size-4 shrink-0" 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="M5 12h14"/>
  <path d="M12 5v14"/>
</svg><bdi dir="auto" class="truncate" x-text="o.label"></bdi></span>
                        </template>
                        <template x-if="!isCreate(o)">
                            <span class="flex min-w-0 flex-col leading-tight">
                                <bdi dir="auto" class="truncate" x-text="text(o)"></bdi>
                                <bdi x-show="o.description" dir="auto" class="truncate text-caption text-muted-foreground" x-text="o.description"></bdi>
                            </span>
                        </template>
                    </span>
                </div>
            </template>
        </div>
    </template>
    <p x-show="createState === 'failed'" x-cloak role="alert" class="mt-1.5 text-caption text-nq-danger-text">Could not create it.</p>
                        <input type="hidden" name="remote_id" :value="value ?? ''">
            </div>
    <div data-slot="relation-picker" x-data="nqRelationPicker(JSON.parse('{\u0022value\u0022:[\u0022c1\u0022,\u0022c3\u0022],\u0022multiple\u0022:true,\u0022options\u0022:[{\u0022value\u0022:\u0022c1\u0022,\u0022label\u0022:\u0022Acme Trading\u0022,\u0022description\u0022:\u0022billing@acme.example\u0022},{\u0022value\u0022:\u0022c2\u0022,\u0022label\u0022:\u0022Nile Logistics\u0022,\u0022description\u0022:\u0022ops@nile.example\u0022},{\u0022value\u0022:\u0022c3\u0022,\u0022label\u0022:\u0022Riyadh Foods\u0022,\u0022labelAr\u0022:\u0022\\u0623\\u063a\\u0630\\u064a\\u0629 \\u0627\\u0644\\u0631\\u064a\\u0627\\u0636\u0022,\u0022description\u0022:\u0022hello@riyadh.example\u0022}],\u0022searchUrl\u0022:null,\u0022resolveUrl\u0022:null,\u0022createUrl\u0022:null,\u0022debounce\u0022:250,\u0022ar\u0022:false,\u0022t\u0022:{\u0022empty\u0022:\u0022No results\u0022,\u0022hint\u0022:\u0022Type to search\u0022,\u0022searching\u0022:\u0022Searching\\u2026\u0022,\u0022error\u0022:\u0022Could not load results.\u0022,\u0022create\u0022:\u0022Create \\u201c{q}\\u201d\u0022,\u0022createFailed\u0022:\u0022Could not create it.\u0022}}'))" x-modelable="value" x-id="['nq-relation']"
    x-bind:data-busy="status === 'loading' || createState === 'busy' ? '' : undefined" class="min-w-0">
            <div data-slot="combobox-chips" 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 flex-wrap px-1.5 py-1">
            <template x-for="v in selected()" :key="v">
                <span data-slot="combobox-chip" class="inline-flex h-6 max-w-full items-center gap-1 rounded-[4px] border border-border bg-secondary ps-2 pe-0.5 text-body-sm text-foreground outline-none data-highlighted:border-nq-focus">
                    <bdi dir="auto" class="min-w-0 truncate" x-text="labelOf(v)"></bdi>
                    <button type="button" data-slot="combobox-chip-remove" tabindex="-1" :aria-label="'Remove' + ' ' + labelOf(v)" @click.stop="remove(v)"
                        class="flex size-5 shrink-0 cursor-default items-center justify-center rounded-[4px] text-muted-foreground outline-none hover:text-foreground [&_svg]:size-3"><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>
                </span>
            </template>
            <input data-slot="combobox-input" x-ref="input" x-bind="input" :placeholder="hasValue() ? undefined : 'Search\u2026'" aria-label="Team"
                                                class="flex-1 border-0 bg-transparent text-body text-foreground outline-none placeholder:text-muted-foreground pointer-coarse:text-[16px] h-6 min-w-16 ps-1.5">
        </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">
                <span class="flex items-center justify-center gap-2" role="status">
                    <span x-show="status === 'loading'" x-cloak class="contents"><svg aria-hidden="true" class="size-4 animate-spin" 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="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg></span>
                    <span x-show="status === 'error'" x-cloak class="contents"><svg aria-hidden="true" class="size-4 text-nq-danger-text" 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="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/>
  <path d="M12 9v4"/>
  <path d="M12 17h.01"/>
</svg></span>
                    <span x-text="emptyText()"></span>
                    <button type="button" x-show="status === 'error'" x-cloak x-on:click="refresh(true)" class="text-foreground underline underline-offset-2">Try again</button>
                </span>
            </div>
            <template x-for="o in rows()" :key="o.value">
                <div data-slot="combobox-item" x-bind="row(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="isSelected(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">
                        <template x-if="isCreate(o)">
                            <span class="flex items-center gap-2 text-foreground"><svg aria-hidden="true" class="size-4 shrink-0" 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="M5 12h14"/>
  <path d="M12 5v14"/>
</svg><bdi dir="auto" class="truncate" x-text="o.label"></bdi></span>
                        </template>
                        <template x-if="!isCreate(o)">
                            <span class="flex min-w-0 flex-col leading-tight">
                                <bdi dir="auto" class="truncate" x-text="text(o)"></bdi>
                                <bdi x-show="o.description" dir="auto" class="truncate text-caption text-muted-foreground" x-text="o.description"></bdi>
                            </span>
                        </template>
                    </span>
                </div>
            </template>
        </div>
    </template>
    <p x-show="createState === 'failed'" x-cloak role="alert" class="mt-1.5 text-caption text-nq-danger-text">Could not create it.</p>
                        <template x-for="v in selected()" :key="v"><input type="hidden" name="team_ids[]" :value="v"></template>
            </div>
</div>
```
