---
title: Dropdown
description: A composable dropdown with slot-based trigger content, outside-click handling, item-based closing, and open/close animations.
---

```tsx
'use client';

import { Avatar } from '@/ui/Avatar';
import { Dropdown } from '@/ui/Dropdown';
import { Button } from '@/ui/buttons/Button';

export function DropdownDemo() {
  const user = { firstName: 'John', lastName: 'Doe' };

  return (
    <Dropdown aria-label="Open user actions">
      <span data-slot="label" className="hidden md:inline text-body">
        {user.firstName} {user.lastName}
      </span>
      <Avatar
        data-slot="label"
        alt={`${user.firstName} ${user.lastName}`}
        className="w-40 h-40 cursor-pointer hover:opacity-80 transition-opacity"
        style={{ width: '40px', height: '40px' }}
      />

      <a href="/account" className="text-b3 font-semibold">
        Account
      </a>
      <Button data-dropdown-item="">Logout</Button>
    </Dropdown>
  );
}
```

## Usage

```tsx showLineNumbers
import { Dropdown } from '@/ui/Dropdown';
import { Avatar } from '@/ui/Avatar';
import { Button } from '@/ui/buttons/Button';

export function Component() {
  const user = { firstName: 'John', lastName: 'Doe' };

  return (
    <Dropdown aria-label="Open user actions">
      <span data-slot="label" className="hidden md:inline text-body">
        {user.firstName} {user.lastName}
      </span>
      <Avatar
        data-slot="label"
        alt={`${user.firstName} ${user.lastName}`}
        className="w-40 h-40 cursor-pointer hover:opacity-80 transition-opacity"
        style={{ width: '40px', height: '40px' }}
      />

      <a href="/account" className="text-b3 font-semibold">
        Account
      </a>
      <Button data-dropdown-item="">Logout</Button>
    </Dropdown>
  );
}
```

### Render-Prop Usage (`close` / `open`)

```tsx showLineNumbers
import { Dropdown } from '@/ui/Dropdown';

export function Component() {
  return (
    <Dropdown aria-label="Open account actions">
      {({ close, open }) => (
        <>
          <span data-slot="label">{open ? 'Account (open)' : 'Account'}</span>
          <button type="button" onClick={close}>
            Logout
          </button>
        </>
      )}
    </Dropdown>
  );
}
```

## API Reference

### Dropdown Props

| Prop        | Type          | Default               | Description                                                    |
| ----------- | ------------- | --------------------- | -------------------------------------------------------------- |
| `icon`      | `IconicNames` | `ArrowOutlinedDown`   | Icon shown on the trigger button                              |
| `className` | `string`      | `undefined`           | Additional classes for the root dropdown container            |
| `children`  | `ReactNode \| ({ close, open, toggle }) => ReactNode` | `undefined` | Slot content (`label`) and overlay content, or render-prop form |
| `...props`  | `button` props| -                     | Standard button attributes passed to the trigger button       |

## Slots

The component is composable through slots using `data-slot`.

| Slot                | Description                                                                 |
| ------------------- | --------------------------------------------------------------------------- |
| `data-slot="label"` | Trigger content. You can provide one or multiple elements (text, avatar...). |

Children without `data-slot="label"` are rendered inside the dropdown overlay panel.

## Behavior

- Clicking the trigger toggles the overlay.
- Clicking outside closes the overlay.
- Clicking a panel link (`a[href]`) closes the overlay.
- Clicking a panel element with `data-dropdown-item` closes the overlay.
- In render-prop mode, call `close()` to close programmatically.
- The overlay stays mounted and uses animation classes for transitions:
  - open: `animate-zoomIn`
  - closing: `animate-zoomOut`
  - hidden state: `opacity-0 scale-90 pointer-events-none`

## Accessibility

- Provide an explicit `aria-label` on `Dropdown` for the trigger.
- Ensure overlay actions are keyboard reachable (buttons/links).
- Keep slot label content meaningful for assistive technologies.
