# Lookup Options Grouping

Since `LookupField` uses a `List` widget internally to render dropdown contents, you can specify `grouping` configuration through the `listOptions` property to organize options into groups.

## Single Level Grouping

Group options by a single key with custom headers and footers. This example groups browsers by favorite status, showing favorites first with a star icon.

```tsx
import { createModel } from "cx/data";
import {
  Controller,
  equal,
  FirstVisibleChildLayout,
  LabelsTopLayout,
  tpl,
  truthy,
} from "cx/ui";
import { Icon, LookupField, PureContainer } from "cx/widgets";
import "../../icons/lucide";

interface Browser {
  id: string;
  text: string;
  favorite: boolean;
}

interface Model {
  browser: string;
  browserOptions: Browser[];
  $group: {
    group: string;
    count: number;
  };
}

const m = createModel<Model>();

const browsers = [
  "Chrome",
  "Firefox",
  "Internet Explorer",
  "Opera",
  "Safari",
  "Edge",
];


class PageController extends Controller {
  onInit() {
    this.store.set(
      m.browserOptions,
      browsers.map((b) => ({
        id: b,
        text: b,
        favorite: b == "Chrome",
      })),
    );
  }
}

export default (
  <LabelsTopLayout controller={PageController}>
    <LookupField
      label="Browser"
      value={m.browser}
      options={m.browserOptions}
      listOptions={{
        grouping: {
          key: {
            group: {
              value: { expr: "{$option.favorite} ? 'Favorites' : 'Other'" },
              direction: "ASC",
            },
          },
          header: (
            <FirstVisibleChildLayout>
              <div class="flex items-center gap-1.5 text-xs uppercase font-semibold text-gray-500 p-2">
                <Icon
                  name="star"
                  visible={equal(m.$group.group, "Favorites")}
                />
                <div text={m.$group.group} />
              </div>
            </FirstVisibleChildLayout>
          ),
        },
        itemStyle: "padding-left: 24px;",
      }}
    />
  </LabelsTopLayout>
);

```

## Multiple Level Grouping

For hierarchical grouping, pass an array of grouping configurations. This example groups users first by operating system, then by browser.

```tsx
import { createModel } from "cx/data";
import { Controller, LabelsTopLayout } from "cx/ui";
import { LookupField } from "cx/widgets";

interface User {
  id: number;
  os: string;
  browser: string;
  fullName: string;
}

interface Model {
  user: number;
  userOptions: User[];
  $group: {
    os: string;
    browser: string;
  };
}

const m = createModel<Model>();

const browsers = [
  "Chrome",
  "Firefox",
  "Internet Explorer",
  "Opera",
  "Safari",
  "Edge",
];
const operatingSystems = ["Windows", "Mac OS", "Ubuntu", "Android", "iOS"];
const firstNames = [
  "Alice",
  "Bob",
  "Charlie",
  "Diana",
  "Edward",
  "Fiona",
  "George",
  "Hannah",
  "Ivan",
  "Julia",
];
const lastNames = [
  "Smith",
  "Johnson",
  "Williams",
  "Brown",
  "Jones",
  "Garcia",
  "Miller",
  "Davis",
  "Wilson",
  "Taylor",
];

class PageController extends Controller {
  onInit() {
    this.store.set(
      m.userOptions,
      Array.from({ length: 50 }).map((_, i) => ({
        id: i + 1,
        os: operatingSystems[i % operatingSystems.length],
        browser: browsers[i % browsers.length],
        fullName: `${firstNames[i % firstNames.length]} ${lastNames[Math.floor(i / 10) % lastNames.length]}`,
      })),
    );
  }
}

export default (
  <div
    layout={{ type: LabelsTopLayout, vertical: true }}
    controller={PageController}
  >
    <LookupField
      label="User"
      value={m.user}
      options={m.userOptions}
      optionTextField="fullName"
      listOptions={{
        grouping: [
          {
            key: {
              os: {
                value: { bind: "$option.os" },
                direction: "ASC",
              },
            },
            header: <div text={m.$group.os} class="font-bold p-2" />,
          },
          {
            key: {
              browser: {
                value: { bind: "$option.browser" },
                direction: "ASC",
              },
            },
            header: (
              <div
                text={m.$group.browser}
                class="text-xs uppercase font-semibold text-gray-500 py-2 pl-6"
              />
            ),
          },
        ],
        itemStyle: "padding-left: 40px;",
      }}
    />
  </div>
);

```

## Configuration

| Property                | Type                | Description                                     |
| ----------------------- | ------------------- | ----------------------------------------------- |
| `listOptions.grouping`  | `object` or `array` | Single grouping config or array for multi-level |
| `listOptions.itemStyle` | `string`            | CSS style applied to each option item           |

### Grouping Object

| Property     | Type     | Description                                             |
| ------------ | -------- | ------------------------------------------------------- |
| `key`        | `object` | Fields to group by with `value` binding and `direction` |
| `aggregates` | `object` | Aggregate calculations (count, sum, etc.)               |
| `header`     | `widget` | Widget rendered before each group                       |
| `footer`     | `widget` | Widget rendered after each group                        |