---
title: Dropdown
description: A menu of actions or choices triggered by a button.
order: 13
tags: [components]
---

import { Preview } from "$lib/components/preview";
import { Button, Dropdown } from "areia";

# Dropdown

A dropdown menu for actions, navigation, and compact option controls.

[Source Code](https://github.com/ilhajs/areia/blob/main/packages/areia/src/components/dropdown/index.ts)

`Dropdown` is backed by `@areia/slots` and wires open state, positioning, keyboard navigation, typeahead, item selection, checkbox items, and radio items.

<Preview
  code={
    'import ilha from "ilha";\nimport { Button, Dropdown } from "areia";\n\nexport default ilha.render(() => (\n  <Dropdown trigger={<Button>Add</Button>}>\n    <Dropdown.Item value="component">Component</Dropdown.Item>\n    <Dropdown.Item value="primitive">Primitive</Dropdown.Item>\n    <Dropdown.Item value="example">Example</Dropdown.Item>\n  </Dropdown>\n));'
  }
  lang="tsx"
>
  <Dropdown trigger={<Button>Add</Button>}>
    <Dropdown.Item value="component">Component</Dropdown.Item>
    <Dropdown.Item value="primitive">Primitive</Dropdown.Item>
    <Dropdown.Item value="example">Example</Dropdown.Item>
  </Dropdown>
</Preview>

## Import

```ts
import { Dropdown } from "areia";
```

## Usage

Prefer composing `Dropdown.Trigger` and `Dropdown.Content` as children. The `trigger`, `children`, and `items` props remain available as shortcuts.

<Preview
  code={
    'import ilha from "ilha";\nimport { Button, Dropdown } from "areia";\n\nexport default ilha.render(() => (\n  <Dropdown>\n    <Dropdown.Trigger>\n      <Button>Menu</Button>\n    </Dropdown.Trigger>\n    <Dropdown.Content>\n      <Dropdown.Item value="edit">Edit</Dropdown.Item>\n      <Dropdown.Item value="duplicate">Duplicate</Dropdown.Item>\n      <Dropdown.Separator />\n      <Dropdown.Item value="delete" variant="danger">\n        Delete\n      </Dropdown.Item>\n    </Dropdown.Content>\n  </Dropdown>\n));'
  }
  lang="tsx"
>
  <Dropdown>
    <Dropdown.Trigger>
      <Button>Menu</Button>
    </Dropdown.Trigger>
    <Dropdown.Content>
      <Dropdown.Item value="edit">Edit</Dropdown.Item>
      <Dropdown.Item value="duplicate">Duplicate</Dropdown.Item>
      <Dropdown.Separator />
      <Dropdown.Item value="delete" variant="danger">
        Delete
      </Dropdown.Item>
    </Dropdown.Content>
  </Dropdown>
</Preview>

`Dropdown` is available as an alias if that reads better in your code.

<Preview
  code={
    'import ilha from "ilha";\nimport { Button, Dropdown } from "areia";\n\nexport default ilha.render(() => (\n  <Dropdown trigger={<Button>Actions</Button>}>\n    <Dropdown.Group>\n      <Dropdown.Label>Project</Dropdown.Label>\n      <Dropdown.Item value="rename">Rename</Dropdown.Item>\n      <Dropdown.Item value="duplicate">Duplicate</Dropdown.Item>\n    </Dropdown.Group>\n    <Dropdown.Separator />\n    <Dropdown.Item value="delete" variant="danger">\n      Delete\n    </Dropdown.Item>\n  </Dropdown>\n));'
  }
  lang="tsx"
>
  <Dropdown trigger={<Button>Actions</Button>}>
    <Dropdown.Group>
      <Dropdown.Label>Project</Dropdown.Label>
      <Dropdown.Item value="rename">Rename</Dropdown.Item>
      <Dropdown.Item value="duplicate">Duplicate</Dropdown.Item>
    </Dropdown.Group>
    <Dropdown.Separator />
    <Dropdown.Item value="delete" variant="danger">
      Delete
    </Dropdown.Item>
  </Dropdown>
</Preview>

Use `Dropdown.Static(...)` for static markup or when you want to initialize behavior yourself. For most application usage, call `Dropdown(...)`.

## Examples

### Basic

<Preview
  code={
    'import ilha from "ilha";\nimport { Button, Dropdown } from "areia";\n\nexport default ilha.render(() => (\n  <Dropdown trigger={<Button>Add</Button>}>\n    <Dropdown.Item value="component">Component</Dropdown.Item>\n    <Dropdown.Item value="primitive">Primitive</Dropdown.Item>\n    <Dropdown.Item value="example">Example</Dropdown.Item>\n  </Dropdown>\n));'
  }
  lang="tsx"
>
  <Dropdown trigger={<Button>Add</Button>}>
    <Dropdown.Item value="component">Component</Dropdown.Item>
    <Dropdown.Item value="primitive">Primitive</Dropdown.Item>
    <Dropdown.Item value="example">Example</Dropdown.Item>
  </Dropdown>
</Preview>

### Inset Items

Use `inset` on items without an icon to align their text with selection indicators or icon-bearing items.

<Preview
  code={
    'import ilha from "ilha";\nimport { Button, Dropdown } from "areia";\n\nexport default ilha.render(() => (\n  <Dropdown trigger={<Button>Edit</Button>}>\n    <Dropdown.Item value="rename">Rename</Dropdown.Item>\n    <Dropdown.Item value="duplicate">Duplicate</Dropdown.Item>\n    <Dropdown.Separator />\n    <Dropdown.Item value="move" inset>\n      Move to folder\n    </Dropdown.Item>\n    <Dropdown.Item value="favorite" inset>\n      Add to favorites\n    </Dropdown.Item>\n    <Dropdown.Separator />\n    <Dropdown.Item value="delete" variant="danger">\n      Delete\n    </Dropdown.Item>\n  </Dropdown>\n));'
  }
  lang="tsx"
>
  <Dropdown trigger={<Button>Edit</Button>}>
    <Dropdown.Item value="rename">Rename</Dropdown.Item>
    <Dropdown.Item value="duplicate">Duplicate</Dropdown.Item>
    <Dropdown.Separator />
    <Dropdown.Item value="move" inset>
      Move to folder
    </Dropdown.Item>
    <Dropdown.Item value="favorite" inset>
      Add to favorites
    </Dropdown.Item>
    <Dropdown.Separator />
    <Dropdown.Item value="delete" variant="danger">
      Delete
    </Dropdown.Item>
  </Dropdown>
</Preview>

### Change Events

Use `onSelect` on the root to respond to accepted item selections.

<Preview
  code={
    'import ilha from "ilha";\nimport { Button, Dropdown } from "areia";\n\nexport default ilha\n  .state("lastAction", "")\n  .render(({ state }) => (\n    <div class="flex flex-col items-start gap-3">\n      <Dropdown\n        trigger={<Button>Actions</Button>}\n        onSelect={(value) => {\n          state.lastAction(value);\n        }}\n      >\n        <Dropdown.Item value="duplicate">\n          Duplicate\n        </Dropdown.Item>\n        <Dropdown.Item value="rename">Rename</Dropdown.Item>\n        <Dropdown.Separator />\n        <Dropdown.Item value="delete" variant="danger">\n          Delete\n        </Dropdown.Item>\n      </Dropdown>\n      <p class="text-sm text-areia-subtle">\n        Last action:{" "}\n        <span class="text-areia-default">\n          {state.lastAction() || "None"}\n        </span>\n      </p>\n    </div>\n  ));'
  }
  lang="tsx"
  codeOnly
/>

### Checkbox Items

Use checkbox items for independently toggleable options.

<Preview
  code={
    'import ilha from "ilha";\nimport { Button, Dropdown } from "areia";\n\nexport default ilha\n  .state("visible", ["sidebar", "wrap"])\n  .render(({ state }) => (\n    <Dropdown\n      trigger={<Button>View Options</Button>}\n      defaultValues={state.visible()}\n      closeOnSelect={false}\n      onValuesChange={(values) => {\n        state.visible(values);\n      }}\n    >\n      <Dropdown.Group>\n        <Dropdown.Label>Display</Dropdown.Label>\n        <Dropdown.CheckboxItem\n          value="sidebar"\n          checked={state.visible().includes("sidebar")}\n        >\n          Show sidebar\n        </Dropdown.CheckboxItem>\n        <Dropdown.CheckboxItem\n          value="lines"\n          checked={state.visible().includes("lines")}\n        >\n          Show line numbers\n        </Dropdown.CheckboxItem>\n        <Dropdown.CheckboxItem\n          value="wrap"\n          checked={state.visible().includes("wrap")}\n        >\n          Word wrap\n        </Dropdown.CheckboxItem>\n      </Dropdown.Group>\n    </Dropdown>\n  ));'
  }
  lang="tsx"
  codeOnly
/>

### Radio Items

Use radio items for a single selected value.

<Preview
  code={
    'import ilha from "ilha";\nimport { Button, Dropdown } from "areia";\n\nexport default ilha\n  .state("density", "comfortable")\n  .render(({ state }) => (\n    <Dropdown\n      trigger={<Button>Density</Button>}\n      defaultValue={state.density()}\n      closeOnSelect={false}\n      onValueChange={(value) => {\n        state.density(value ?? "comfortable");\n      }}\n    >\n      <Dropdown.Label>Table density</Dropdown.Label>\n      <Dropdown.RadioItem\n        value="compact"\n        checked={state.density() === "compact"}\n      >\n        Compact\n      </Dropdown.RadioItem>\n      <Dropdown.RadioItem\n        value="comfortable"\n        checked={state.density() === "comfortable"}\n      >\n        Comfortable\n      </Dropdown.RadioItem>\n      <Dropdown.RadioItem\n        value="spacious"\n        checked={state.density() === "spacious"}\n      >\n        Spacious\n      </Dropdown.RadioItem>\n    </Dropdown>\n  ));'
  }
  lang="tsx"
  codeOnly
/>

### Custom Trigger

Pass any Areia or Ilha-rendered content as the trigger.

<Preview
  code={
    'import ilha from "ilha";\nimport { Dropdown } from "areia";\n\nexport default ilha.render(() => (\n  <Dropdown\n    trigger={\n      <span class="flex size-8 items-center justify-center rounded-full bg-areia-accent text-sm font-medium text-white">\n        AR\n      </span>\n    }\n    triggerClass="rounded-full"\n  >\n    <Dropdown.Item value="profile">Profile</Dropdown.Item>\n    <Dropdown.Item value="settings">Settings</Dropdown.Item>\n    <Dropdown.Separator />\n    <Dropdown.Item value="logout" variant="danger">\n      Log out\n    </Dropdown.Item>\n  </Dropdown>\n));'
  }
  lang="tsx"
>
  <Dropdown
    trigger={
      <span class="flex size-8 items-center justify-center rounded-full bg-areia-accent text-sm font-medium text-white">
        AR
      </span>
    }
    triggerClass="rounded-full"
  >
    <Dropdown.Item value="profile">Profile</Dropdown.Item>
    <Dropdown.Item value="settings">Settings</Dropdown.Item>
    <Dropdown.Separator />
    <Dropdown.Item value="logout" variant="danger">
      Log out
    </Dropdown.Item>
  </Dropdown>
</Preview>

### Navigation Links

Use `Dropdown.LinkItem` for semantic links.

<Preview
  code={
    'import ilha from "ilha";\nimport { Button, Dropdown } from "areia";\n\nexport default ilha.render(() => (\n  <Dropdown trigger={<Button>Resources</Button>}>\n    <Dropdown.LinkItem href="/settings" value="settings">\n      Settings\n    </Dropdown.LinkItem>\n    <Dropdown.LinkItem href="/docs" value="docs">\n      Documentation\n    </Dropdown.LinkItem>\n    <Dropdown.Separator />\n    <Dropdown.LinkItem\n      href="https://ilha.build/llms.txt"\n      external\n      value="ilha-llms"\n    >\n      Ilha llms.txt\n    </Dropdown.LinkItem>\n  </Dropdown>\n));'
  }
  lang="tsx"
>
  <Dropdown trigger={<Button>Resources</Button>}>
    <Dropdown.LinkItem href="/settings" value="settings">
      Settings
    </Dropdown.LinkItem>
    <Dropdown.LinkItem href="/docs" value="docs">
      Documentation
    </Dropdown.LinkItem>
    <Dropdown.Separator />
    <Dropdown.LinkItem
      href="https://ilha.build/llms.txt"
      external
      value="ilha-llms"
    >
      Ilha llms.txt
    </Dropdown.LinkItem>
  </Dropdown>
</Preview>

## API Reference

### Dropdown

Root component that manages the dropdown state.

| Prop               | Type                                     | Default    | Description                                                                           |
| ------------------ | ---------------------------------------- | ---------- | ------------------------------------------------------------------------------------- |
| `trigger`          | `unknown`                                | -          | Content rendered inside the trigger button.                                           |
| `children`         | `unknown`                                | -          | Composed dropdown slots, or menu content when no `Dropdown.Content` child is present. |
| `items`            | `DropdownItemInput[]`                    | -          | Convenience item descriptors. Ignored when `children` is provided.                    |
| `defaultOpen`      | `boolean`                                | `false`    | Initial open state.                                                                   |
| `defaultValue`     | `string \| null`                         | `null`     | Initial radio item value.                                                             |
| `defaultValues`    | `string[]`                               | `[]`       | Initial checkbox item values.                                                         |
| `closeOnSelect`    | `boolean`                                | `true`     | Whether selecting an item closes the menu.                                            |
| `side`             | `"top" \| "right" \| "bottom" \| "left"` | `"bottom"` | Preferred side for the popup.                                                         |
| `align`            | `"start" \| "center" \| "end"`           | `"start"`  | Preferred alignment relative to the trigger.                                          |
| `onSelect`         | `(value: string) => void`                | -          | Fires when a user selects an item.                                                    |
| `onValueChange`    | `(value: string \| null) => void`        | -          | Fires when the radio value changes.                                                   |
| `onValuesChange`   | `(values: string[]) => void`             | -          | Fires when checkbox values change.                                                    |
| `onOpenChange`     | `(open: boolean) => void`                | -          | Called when open state changes.                                                       |
| `onPortalMounted`  | `(container: HTMLElement) => void`       | -          | After portaled menu mounts on open. See Dialog docs, **Ilha + portaled overlays**.    |
| `triggerClassName` | `string`                                 | -          | Alias for `triggerClass`.                                                             |
| `contentClassName` | `string`                                 | -          | Alias for `contentClass`.                                                             |

### Dropdown.Trigger

Button that opens the dropdown.

Accepts standard button attributes plus `class` and `className`.

### Dropdown.Content

Popup container for menu content.

Accepts standard div attributes plus `class` and `className`.

### Dropdown.Item

Individual menu item for actions.

| Prop       | Type                    | Default     | Description                                    |
| ---------- | ----------------------- | ----------- | ---------------------------------------------- |
| `value`    | `string`                | -           | Selection value emitted by events.             |
| `children` | `unknown`               | -           | Item content.                                  |
| `label`    | `unknown`               | -           | Convenience label when using item descriptors. |
| `icon`     | `unknown`               | -           | Content displayed before the label.            |
| `shortcut` | `unknown`               | -           | Content displayed at the end of the item.      |
| `variant`  | `"default" \| "danger"` | `"default"` | Visual style of the item.                      |
| `selected` | `boolean`               | `false`     | Shows the selection indicator initially.       |
| `inset`    | `boolean`               | `false`     | Adds left padding to align text.               |
| `disabled` | `boolean`               | `false`     | Disables interaction.                          |

### Dropdown.LinkItem

A menu item rendered as an anchor.

| Prop       | Type                    | Default     | Description                                    |
| ---------- | ----------------------- | ----------- | ---------------------------------------------- |
| `href`     | `string`                | -           | URL to navigate to.                            |
| `external` | `boolean`               | `false`     | Adds `target="_blank"` and `rel="noreferrer"`. |
| `variant`  | `"default" \| "danger"` | `"default"` | Visual style of the item.                      |
| `inset`    | `boolean`               | `false`     | Adds left padding to align text.               |

### Dropdown.CheckboxItem

A menu item that toggles membership in the root `values` array.

| Prop       | Type      | Default | Description                                         |
| ---------- | --------- | ------- | --------------------------------------------------- |
| `value`    | `string`  | -       | Checkbox value.                                     |
| `checked`  | `boolean` | `false` | Initial checked state and rendered indicator state. |
| `disabled` | `boolean` | `false` | Disables interaction.                               |

### Dropdown.RadioItem

A menu item that sets the root `value`.

| Prop       | Type      | Default | Description                                         |
| ---------- | --------- | ------- | --------------------------------------------------- |
| `value`    | `string`  | -       | Radio value.                                        |
| `checked`  | `boolean` | `false` | Initial checked state and rendered indicator state. |
| `disabled` | `boolean` | `false` | Disables interaction.                               |

### Dropdown.Label

Non-interactive label for a group of items.

### Dropdown.Group

Wrapper for grouping related labels and items.

### Dropdown.Separator

Visual divider between menu sections.

### Dropdown.Shortcut

Trailing shortcut hint for an item.
