---
name: dropdown-menu
title: Dropdown Menu
url: https://ui.frontic.com/components/ui/dropdown-menu.md
tier: ui
install: npx @frontic/ui add dropdown-menu
files:
  - components/ui/dropdown-menu/DropdownMenu.vue
  - components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue
  - components/ui/dropdown-menu/DropdownMenuContent.vue
  - components/ui/dropdown-menu/DropdownMenuGroup.vue
  - components/ui/dropdown-menu/DropdownMenuItem.vue
  - components/ui/dropdown-menu/DropdownMenuLabel.vue
  - components/ui/dropdown-menu/DropdownMenuPortal.vue
  - components/ui/dropdown-menu/DropdownMenuRadioGroup.vue
  - components/ui/dropdown-menu/DropdownMenuRadioItem.vue
  - components/ui/dropdown-menu/DropdownMenuSeparator.vue
  - components/ui/dropdown-menu/DropdownMenuShortcut.vue
  - components/ui/dropdown-menu/DropdownMenuSub.vue
  - components/ui/dropdown-menu/DropdownMenuSubContent.vue
  - components/ui/dropdown-menu/DropdownMenuSubTrigger.vue
  - components/ui/dropdown-menu/DropdownMenuTrigger.vue
  - components/ui/dropdown-menu/index.ts
dependencies:
  - "@lucide/vue"
  - "@vueuse/core"
  - class-variance-authority
  - reka-ui
---

# Dropdown Menu

A menu that opens from a button, with actions, checkbox and radio items, labelled groups and destructive entries, such as account or sort options.

## Install

```sh
npx @frontic/ui add dropdown-menu
```

Used by: [Recent Orders](https://ui.frontic.com/components/sections/recent-orders.md), [Team Members](https://ui.frontic.com/components/sections/team-members.md)

npm packages: `@lucide/vue`, `@vueuse/core`, `class-variance-authority`, `reka-ui`

## Examples

```vue
<script setup lang="ts">
import { PackageIcon, MapPinIcon, HeartIcon, GlobeIcon, LogOutIcon } from '@lucide/vue'

import { ref } from 'vue'
import { Button } from '@/components/ui/button'
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuRadioGroup,
  DropdownMenuRadioItem,
  DropdownMenuSeparator,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'

const markets = [
  { value: 'de', label: 'Germany · EUR' },
  { value: 'at', label: 'Austria · EUR' },
  { value: 'ch', label: 'Switzerland · CHF' },
]
const market = ref('de')
const offers = ref(true)
</script>

<template>
  <DropdownMenu default-open>
    <DropdownMenuTrigger as-child><Button variant="outline" color="neutral">Account</Button></DropdownMenuTrigger>
    <DropdownMenuContent>
      <DropdownMenuLabel>
        Lena Huber
        <span class="block font-normal text-muted-foreground normal-case">lena.huber@example.com</span>
      </DropdownMenuLabel>
      <DropdownMenuSeparator />
      <DropdownMenuGroup>
        <DropdownMenuItem>
          <PackageIcon data-icon />
          Orders
        </DropdownMenuItem>
        <DropdownMenuItem>
          <MapPinIcon data-icon />
          Addresses
        </DropdownMenuItem>
        <DropdownMenuItem>
          <HeartIcon data-icon />
          Wishlist
        </DropdownMenuItem>
        <DropdownMenuSub>
          <DropdownMenuSubTrigger>
            <GlobeIcon data-icon />
            Country
          </DropdownMenuSubTrigger>
          <DropdownMenuSubContent>
            <DropdownMenuRadioGroup v-model="market">
              <DropdownMenuRadioItem v-for="option in markets" :key="option.value" :value="option.value">{{ option.label }}</DropdownMenuRadioItem>
            </DropdownMenuRadioGroup>
          </DropdownMenuSubContent>
        </DropdownMenuSub>
      </DropdownMenuGroup>
      <DropdownMenuSeparator />
      <DropdownMenuCheckboxItem v-model="offers">Email me offers</DropdownMenuCheckboxItem>
      <DropdownMenuSeparator />
      <DropdownMenuItem color="destructive">
        <LogOutIcon data-icon />
        Sign out
      </DropdownMenuItem>
    </DropdownMenuContent>
  </DropdownMenu>
</template>
```

The example also uses `button`, which `add dropdown-menu` leaves out: `npx @frontic/ui add button`.

## Anatomy

```vue
<DropdownMenu>
  <DropdownMenuTrigger />
  <DropdownMenuContent>
    <DropdownMenuLabel />
    <DropdownMenuSeparator />
    <DropdownMenuGroup>
      <DropdownMenuItem />
      <DropdownMenuSub>
        <DropdownMenuSubTrigger />
        <DropdownMenuSubContent>
          <DropdownMenuRadioGroup>
            <DropdownMenuRadioItem />
          </DropdownMenuRadioGroup>
        </DropdownMenuSubContent>
      </DropdownMenuSub>
    </DropdownMenuGroup>
    <DropdownMenuCheckboxItem />
    <DropdownMenuItem />
  </DropdownMenuContent>
</DropdownMenu>
```

## API reference

### DropdownMenu

Groups all parts of the dropdown menu.

`data-slot="dropdown-menu"` · `DropdownMenu.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `defaultOpen` | `boolean` | `false` | The open state of the dropdown menu when it is initially rendered. Use when you do not need to control its open state. |
| `open` | `boolean` |  | The controlled open state of the menu. Can be used as `v-model:open`. |
| `dir` | `Direction`: `'ltr' \| 'rtl'` |  | The reading direction of the combobox when applicable.<br><br>If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode. |
| `modal` | `boolean` | `true` | The modality of the dropdown menu.<br><br>When set to `true`, interaction with outside elements will be disabled and only menu content will be visible to screen readers. |

| Event | Payload | Description |
| --- | --- | --- |
| `update:open` | `payload: boolean` | Fires with the new value when `open` changes; `v-model:open` binds it. |

| Slot | Slot props | Description |
| --- | --- | --- |
| `default` | `{ open: boolean; }` | Holds the menu's trigger and content; gets whether the menu is open. |

### DropdownMenuCheckboxItem

Lets the user switch an option on or off from the menu.

`data-slot="dropdown-menu-checkbox-item"` · `DropdownMenuCheckboxItem.vue`

Styling: `dropdown-menu-item`, which extends [`menu-item`](https://ui.frontic.com/DESIGN.md#menu-item) and [`menu-item-destructive`](https://ui.frontic.com/DESIGN.md#menu-item-destructive). Change them there and every part that extends them follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `modelValue` | `CheckedState`: `boolean \| 'indeterminate'` | `false` | The controlled checked state of the item. Can be used as `v-model`. |
| `disabled` | `boolean` | `false` | When `true`, prevents the user from interacting with the item. |
| `textValue` | `string` |  | Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item.<br><br>Use this when the content is complex, or you have non-textual content inside. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Event | Payload | Description |
| --- | --- | --- |
| `update:modelValue` | `payload: boolean` | Event handler called when the checked state changes. |
| `select` | `event: Event` | Event handler called when the user selects an item (via mouse or keyboard).<br><br>Calling `event.preventDefault` in this handler will prevent the menu from closing when selecting that item. |

| Slot | Slot props | Description |
| --- | --- | --- |
| `indicator-icon` |  | Replaces the check icon shown while the option is on. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-disabled` |  | Present while the part is disabled. |
| `data-highlighted` |  | Present while the item is highlighted by the pointer or the keyboard. |
| `data-state` | `'checked' \| 'unchecked' \| 'indeterminate'` | The state the part is in, one value per state. |

### DropdownMenuContent

Holds the entries the dropdown menu shows while open.

`data-slot="dropdown-menu-content"` · `DropdownMenuContent.vue`

Styling: `dropdown-menu-content`, which extends [`overlay`](https://ui.frontic.com/DESIGN.md#overlay). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `forceMount` | `boolean` | `false` | Used to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `loop` | `boolean` | `false` | When `true`, keyboard navigation will loop from last item to first, and vice versa. |
| `reference` | `ReferenceElement`: `Element \| VirtualElement` |  | The custom element or virtual element that will be set as the reference to position the floating element.<br><br>If provided, it will replace the default anchor element. |
| `memoDependencies` | `unknown[]` |  | Reactive dependencies that should invalidate the memoized content subtree. |
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'bottom'` | The preferred side of the trigger to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled. |
| `sideOffset` | `number` | `4` | The distance in pixels from the trigger. |
| `sideFlip` | `boolean` | `true` | Flip to the opposite side when colliding with boundary. |
| `align` | `'center' \| 'start' \| 'end'` | `'start'` | The preferred alignment against the trigger. May change when collisions occur. |
| `alignOffset` | `number` | `0` | An offset in pixels from the `start` or `end` alignment options. |
| `alignFlip` | `boolean` | `true` | Flip alignment when colliding with boundary. May only occur when `prioritizePosition` is true. |
| `avoidCollisions` | `boolean` | `true` | When `true`, overrides the side and align preferences to prevent collisions with boundary edges. |
| `collisionBoundary` | `Element \| (Element \| null)[] \| null`: `null \| Element \| (Element \| null)[]` | `[]` | The element used as the collision boundary. By default this is the viewport, though you can provide additional element(s) to be included in this check. |
| `collisionPadding` | `number \| Partial<Record<'top' \| 'right' \| 'bottom' \| 'left', number>>` | `0` | The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { top: 20, left: 20 }. |
| `arrowPadding` | `number` | `0` | The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. |
| `hideShiftedArrow` | `boolean` | `true` | When `true`, hides the arrow when it cannot be centered to the reference element. |
| `sticky` | `'partial' \| 'always'` | `'partial'` | The sticky behavior on the align axis. `partial` will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless. |
| `hideWhenDetached` | `boolean` | `false` | Whether to hide the content when the trigger becomes fully occluded. |
| `positionStrategy` | `'absolute' \| 'fixed'` |  | The type of CSS position property to use. |
| `updatePositionStrategy` | `'always' \| 'optimized'` | `'optimized'` | Strategy to update the position of the floating element on every animation frame. |
| `disableUpdateOnLayoutShift` | `boolean` | `false` | Whether to disable the update position for the content when the layout shifted. |
| `prioritizePosition` | `boolean` | `false` | Force content to be position within the viewport.<br><br>Might overlap the reference element, which may not be desired. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Event | Payload | Description |
| --- | --- | --- |
| `escapeKeyDown` | `event: KeyboardEvent` | Event handler called when the escape key is down. Can be prevented. |
| `pointerDownOutside` | `event: PointerDownOutsideEvent` | Event handler called when a `pointerdown` event happens outside of the `DismissableLayer`. Can be prevented. |
| `focusOutside` | `event: FocusOutsideEvent` | Event handler called when the focus moves outside of the `DismissableLayer`. Can be prevented. |
| `interactOutside` | `event: PointerDownOutsideEvent \| FocusOutsideEvent` | Event handler called when an interaction happens outside the `DismissableLayer`. Specifically, when a `pointerdown` event happens outside or focus moves outside of it. Can be prevented. |
| `openAutoFocus` | `event: Event` | Fires when focus moves into the content as it opens; call `preventDefault()` to keep focus where it is. |
| `closeAutoFocus` | `event: Event` | Event handler called when auto-focusing on close. Can be prevented. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-align` | `'start' \| 'center' \| 'end'` | How the content lines up with its trigger: as `align` asks, unless there was no room. |
| `data-dismissable-layer` |  | Marks a layer that closes on Escape or a click outside it. |
| `data-side` | `'top' \| 'right' \| 'bottom' \| 'left'` | The side the content opened on: the one `side` asks for, unless there was no room. |
| `data-state` | `'open' \| 'closed'` | The state the part is in, one value per state. |

| CSS variable | Description |
| --- | --- |
| `--reka-dropdown-menu-content-available-height` | The height the content has between its trigger and the edge of the screen. |
| `--reka-dropdown-menu-content-available-width` | The width the content has between its trigger and the edge of the screen. |
| `--reka-dropdown-menu-content-transform-origin` | The point the content grows from, on the side facing its trigger, for its open and close animation. |
| `--reka-dropdown-menu-trigger-height` | The trigger's height. |
| `--reka-dropdown-menu-trigger-width` | The trigger's width, to size the content to match. |

### DropdownMenuGroup

Groups related entries of the dropdown menu.

`data-slot="dropdown-menu-group"` · `DropdownMenuGroup.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |

### DropdownMenuItem

Holds one action the user can pick from the dropdown menu.

`data-slot="dropdown-menu-item"` · `DropdownMenuItem.vue`

Styling: `dropdown-menu-item`, which extends [`menu-item`](https://ui.frontic.com/DESIGN.md#menu-item) and [`menu-item-destructive`](https://ui.frontic.com/DESIGN.md#menu-item-destructive). Change them there and every part that extends them follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `disabled` | `boolean` | `false` | When `true`, prevents the user from interacting with the item. |
| `textValue` | `string` |  | Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item.<br><br>Use this when the content is complex, or you have non-textual content inside. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |
| `inset` | `boolean` | `false` | Indents the item to line up with items that show a check or icon. |
| `color` | `'neutral' \| 'destructive'` | `'neutral'` | The item's intent: destructive marks an action that deletes or cannot be undone, such as removing an address. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-color` | `'neutral' \| 'destructive'` | Carries the `color` prop. |
| `data-disabled` |  | Present while the part is disabled. |
| `data-highlighted` |  | Present while the item is highlighted by the pointer or the keyboard. |
| `data-inset` |  | Present when `inset` indents the item to line up with items that have an icon. |

### DropdownMenuLabel

Labels a group of entries in the dropdown menu.

`data-slot="dropdown-menu-label"` · `DropdownMenuLabel.vue`

Styling: `dropdown-menu-label`, which extends [`menu-label`](https://ui.frontic.com/DESIGN.md#menu-label). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |
| `inset` | `boolean` | `false` | Indents the label to line up with items that show a check or icon. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-inset` |  | Present when `inset` indents the item to line up with items that have an icon. |

### DropdownMenuPortal

Places the menu content above the rest of the page.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `to` | `string \| HTMLElement` |  | Vue native teleport component prop `:to`<br><br>[vuejs.org/guide/built-ins/teleport.html#basic-usage](https://vuejs.org/guide/built-ins/teleport.html#basic-usage) |
| `disabled` | `boolean` | `false` | Disable teleport and render the component inline<br><br>[vuejs.org/guide/built-ins/teleport.html#disabling-teleport](https://vuejs.org/guide/built-ins/teleport.html#disabling-teleport) |
| `defer` | `boolean` | `false` | Defer the resolving of a Teleport target until other parts of the application have mounted (requires Vue 3.5.0+)<br><br>[vuejs.org/guide/built-ins/teleport.html#deferred-teleport](https://vuejs.org/guide/built-ins/teleport.html#deferred-teleport) |
| `forceMount` | `boolean` | `false` | Used to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. |

### DropdownMenuRadioGroup

Groups radio items so the user can pick exactly one.

`data-slot="dropdown-menu-radio-group"` · `DropdownMenuRadioGroup.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `modelValue` | `AcceptableValue`: `null \| string \| number \| bigint \| Record<string, any>` |  | The value of the selected item in the group. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |

| Event | Payload | Description |
| --- | --- | --- |
| `update:modelValue` | `payload: AcceptableValue` | Event handler called when the value changes. |

### DropdownMenuRadioItem

Lets the user choose one option from a group in the menu.

`data-slot="dropdown-menu-radio-item"` · `DropdownMenuRadioItem.vue`

Styling: `dropdown-menu-item`, which extends [`menu-item`](https://ui.frontic.com/DESIGN.md#menu-item) and [`menu-item-destructive`](https://ui.frontic.com/DESIGN.md#menu-item-destructive). Change them there and every part that extends them follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` (required) | `AcceptableValue`: `null \| string \| number \| bigint \| Record<string, any>` |  | The unique value of the item. |
| `disabled` | `boolean` | `false` | When `true`, prevents the user from interacting with the item. |
| `textValue` | `string` |  | Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item.<br><br>Use this when the content is complex, or you have non-textual content inside. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Event | Payload | Description |
| --- | --- | --- |
| `select` | `event: Event` | Event handler called when the user selects an item (via mouse or keyboard).<br><br>Calling `event.preventDefault` in this handler will prevent the menu from closing when selecting that item. |

| Slot | Slot props | Description |
| --- | --- | --- |
| `indicator-icon` |  | Replaces the check icon shown on the chosen option. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-disabled` |  | Present while the part is disabled. |
| `data-highlighted` |  | Present while the item is highlighted by the pointer or the keyboard. |
| `data-state` | `'checked' \| 'unchecked' \| 'indeterminate'` | The state the part is in, one value per state. |

### DropdownMenuSeparator

Separates groups of entries in the dropdown menu.

`data-slot="dropdown-menu-separator"` · `DropdownMenuSeparator.vue`

Styling: `dropdown-menu-separator`, which extends [`divider`](https://ui.frontic.com/DESIGN.md#divider). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

### DropdownMenuShortcut

Shows the keyboard shortcut for a menu item. Renders a `<span>`.

`data-slot="dropdown-menu-shortcut"` · `DropdownMenuShortcut.vue`

Styling: `dropdown-menu-shortcut`, which extends [`menu-shortcut`](https://ui.frontic.com/DESIGN.md#menu-shortcut). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'span'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

### DropdownMenuSub

Groups a submenu trigger with the nested menu it opens.

`data-slot="dropdown-menu-sub"` · `DropdownMenuSub.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `defaultOpen` | `boolean` | `false` | The open state of the dropdown menu when it is initially rendered. Use when you do not need to control its open state. |
| `open` | `boolean` |  | The controlled open state of the menu. Can be used as `v-model:open`. |

| Event | Payload | Description |
| --- | --- | --- |
| `update:open` | `payload: boolean` | Event handler called when the open state of the submenu changes. |

| Slot | Slot props | Description |
| --- | --- | --- |
| `default` | `{ open: boolean; }` | Holds the submenu's trigger and content; gets whether the submenu is open. |

### DropdownMenuSubContent

Holds the entries the submenu shows while open.

`data-slot="dropdown-menu-sub-content"` · `DropdownMenuSubContent.vue`

Styling: `dropdown-menu-sub-content`, which extends [`overlay`](https://ui.frontic.com/DESIGN.md#overlay). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `forceMount` | `boolean` | `false` | Used to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `loop` | `boolean` | `false` | When `true`, keyboard navigation will loop from last item to first, and vice versa. |
| `reference` | `ReferenceElement`: `Element \| VirtualElement` |  | The custom element or virtual element that will be set as the reference to position the floating element.<br><br>If provided, it will replace the default anchor element. |
| `memoDependencies` | `unknown[]` |  | Reactive dependencies that should invalidate the memoized content subtree. |
| `sideOffset` | `number` | `0` | The distance in pixels from the trigger. |
| `sideFlip` | `boolean` | `true` | Flip to the opposite side when colliding with boundary. |
| `alignOffset` | `number` | `0` | An offset in pixels from the `start` or `end` alignment options. |
| `alignFlip` | `boolean` | `true` | Flip alignment when colliding with boundary. May only occur when `prioritizePosition` is true. |
| `avoidCollisions` | `boolean` | `true` | When `true`, overrides the side and align preferences to prevent collisions with boundary edges. |
| `collisionBoundary` | `Element \| (Element \| null)[] \| null`: `null \| Element \| (Element \| null)[]` | `[]` | The element used as the collision boundary. By default this is the viewport, though you can provide additional element(s) to be included in this check. |
| `collisionPadding` | `number \| Partial<Record<'top' \| 'right' \| 'bottom' \| 'left', number>>` | `0` | The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { top: 20, left: 20 }. |
| `arrowPadding` | `number` | `0` | The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. |
| `hideShiftedArrow` | `boolean` | `true` | When `true`, hides the arrow when it cannot be centered to the reference element. |
| `sticky` | `'partial' \| 'always'` | `'partial'` | The sticky behavior on the align axis. `partial` will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless. |
| `hideWhenDetached` | `boolean` | `false` | Whether to hide the content when the trigger becomes fully occluded. |
| `positionStrategy` | `'absolute' \| 'fixed'` |  | The type of CSS position property to use. |
| `updatePositionStrategy` | `'always' \| 'optimized'` | `'optimized'` | Strategy to update the position of the floating element on every animation frame. |
| `disableUpdateOnLayoutShift` | `boolean` | `false` | Whether to disable the update position for the content when the layout shifted. |
| `prioritizePosition` | `boolean` | `false` | Force content to be position within the viewport.<br><br>Might overlap the reference element, which may not be desired. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Event | Payload | Description |
| --- | --- | --- |
| `escapeKeyDown` | `event: KeyboardEvent` | Event handler called when the escape key is down. Can be prevented. |
| `pointerDownOutside` | `event: PointerDownOutsideEvent` | Event handler called when a `pointerdown` event happens outside of the `DismissableLayer`. Can be prevented. |
| `focusOutside` | `event: FocusOutsideEvent` | Event handler called when the focus moves outside of the `DismissableLayer`. Can be prevented. |
| `interactOutside` | `event: PointerDownOutsideEvent \| FocusOutsideEvent` | Event handler called when an interaction happens outside the `DismissableLayer`. Specifically, when a `pointerdown` event happens outside or focus moves outside of it. Can be prevented. |
| `openAutoFocus` | `event: Event` | Fires when focus moves into the content as it opens; call `preventDefault()` to keep focus where it is. |
| `closeAutoFocus` | `event: Event` | Event handler called when auto-focusing on close. Can be prevented. |
| `entryFocus` | `event: Event` | Fires when keyboard focus enters the list of items; call `preventDefault()` to stop the first item taking it. |

| CSS variable | Description |
| --- | --- |
| `--reka-dropdown-menu-content-available-height` | The height the content has between its trigger and the edge of the screen. |
| `--reka-dropdown-menu-content-available-width` | The width the content has between its trigger and the edge of the screen. |
| `--reka-dropdown-menu-content-transform-origin` | The point the content grows from, on the side facing its trigger, for its open and close animation. |
| `--reka-dropdown-menu-trigger-height` | The trigger's height. |
| `--reka-dropdown-menu-trigger-width` | The trigger's width, to size the content to match. |

### DropdownMenuSubTrigger

Opens a submenu from an item of the dropdown menu.

`data-slot="dropdown-menu-sub-trigger"` · `DropdownMenuSubTrigger.vue`

Styling: `dropdown-menu-sub-trigger`, which extends [`menu-item`](https://ui.frontic.com/DESIGN.md#menu-item). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `graceDuration` | `number` | `300` | How long (in milliseconds) the pointer is given to reach the submenu after leaving the trigger. While it moves towards the submenu within this time, hovering other items won't close the submenu. Increase it for users who move the pointer slowly or on devices under heavy load. |
| `disabled` | `boolean` | `false` | When `true`, prevents the user from interacting with the item. |
| `textValue` | `string` |  | Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item.<br><br>Use this when the content is complex, or you have non-textual content inside. |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` |  | The element or component this component should render as. Can be overwritten by `asChild`. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |
| `inset` | `boolean` | `false` | Indents the trigger to line up with items that show a check or icon. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-disabled` |  | Present while the part is disabled. |
| `data-highlighted` |  | Present while the item is highlighted by the pointer or the keyboard. |
| `data-inset` |  | Present when `inset` indents the item to line up with items that have an icon. |
| `data-state` | `'open' \| 'closed'` | The state the part is in, one value per state. |

### DropdownMenuTrigger

Opens and closes the dropdown menu. Renders a `<button>`.

`data-slot="dropdown-menu-trigger"` · `DropdownMenuTrigger.vue`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `disabled` | `boolean` | `false` | When `true`, prevents the user from interacting with item |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'button'` | The element or component this component should render as. Can be overwritten by `asChild`. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-disabled` |  | Present while the part is disabled. |
| `data-state` | `'open' \| 'closed'` | The state the part is in, one value per state. |

## Styling

| Part | Recipe |
| --- | --- |
| `content` | [`dropdown-menu-content`](https://ui.frontic.com/DESIGN.md#dropdown-menu-content) |
| `sub-content` | [`dropdown-menu-sub-content`](https://ui.frontic.com/DESIGN.md#dropdown-menu-sub-content) |
| `item` | [`dropdown-menu-item`](https://ui.frontic.com/DESIGN.md#dropdown-menu-item) |
| `sub-trigger` | [`dropdown-menu-sub-trigger`](https://ui.frontic.com/DESIGN.md#dropdown-menu-sub-trigger) |
| `label` | [`dropdown-menu-label`](https://ui.frontic.com/DESIGN.md#dropdown-menu-label) |
| `separator` | [`dropdown-menu-separator`](https://ui.frontic.com/DESIGN.md#dropdown-menu-separator) |
| `shortcut` | [`dropdown-menu-shortcut`](https://ui.frontic.com/DESIGN.md#dropdown-menu-shortcut) |
| `disabled` | [`disabled`](https://ui.frontic.com/DESIGN.md#disabled) |

States with a look of their own: focus and disabled.

## Source

`components/ui/dropdown-menu/DropdownMenu.vue`

```vue
<script lang="ts">
/** Groups all parts of the dropdown menu. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuRootEmits, DropdownMenuRootProps } from 'reka-ui'
import { DropdownMenuRoot, useForwardPropsEmits } from 'reka-ui'

const props = defineProps<DropdownMenuRootProps>()
const emits = defineEmits<DropdownMenuRootEmits>()

defineSlots<{
  /** Holds the menu's trigger and content; gets whether the menu is open. */
  default?: (props: { open: boolean }) => unknown
}>()

const forwarded = useForwardPropsEmits(props, emits)
</script>

<template>
  <DropdownMenuRoot v-slot="slotProps" data-slot="dropdown-menu" v-bind="forwarded">
    <slot v-bind="slotProps" />
  </DropdownMenuRoot>
</template>
```

`components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue`

```vue
<script lang="ts">
/** Lets the user switch an option on or off from the menu. */
export default {}
</script>

<script setup lang="ts">
import { CheckIcon } from '@lucide/vue'

import type { DropdownMenuCheckboxItemEmits, DropdownMenuCheckboxItemProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { DropdownMenuCheckboxItem, DropdownMenuItemIndicator, useForwardPropsEmits } from 'reka-ui'

const props = defineProps<DropdownMenuCheckboxItemProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<DropdownMenuCheckboxItemEmits>()

defineSlots<{
  /** Replaces the check icon shown while the option is on. */
  'indicator-icon'?: () => unknown
  default?: () => unknown
}>()

const delegatedProps = reactiveOmit(props, 'class')

const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>

<template>
  <DropdownMenuCheckboxItem
    data-slot="dropdown-menu-checkbox-item"
    v-bind="forwarded"
    :class="[
      'fui-dropdown-menu-item fui-dropdown-menu-item-indicator relative cursor-default outline-hidden select-none data-disabled:pointer-events-none data-disabled:fui-disabled **:data-icon:pointer-events-none **:data-icon:shrink-0',
      props.class,
    ]"
  >
    <span class="pointer-events-none absolute inset-e-2 flex items-center justify-center" data-slot="dropdown-menu-checkbox-item-indicator">
      <DropdownMenuItemIndicator>
        <slot name="indicator-icon">
          <CheckIcon data-icon />
        </slot>
      </DropdownMenuItemIndicator>
    </span>
    <slot />
  </DropdownMenuCheckboxItem>
</template>
```

`components/ui/dropdown-menu/DropdownMenuContent.vue`

```vue
<script lang="ts">
/** Holds the entries the dropdown menu shows while open. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuContentEmits, DropdownMenuContentProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { DropdownMenuContent, DropdownMenuPortal, useForwardPropsEmits } from 'reka-ui'

defineOptions({
  inheritAttrs: false,
})

const props = withDefaults(defineProps<DropdownMenuContentProps & { class?: HTMLAttributes['class'] }>(), {
  align: 'start',
  sideOffset: 4,
})
const emits = defineEmits<DropdownMenuContentEmits>()

const delegatedProps = reactiveOmit(props, 'class')

const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>

<template>
  <DropdownMenuPortal>
    <DropdownMenuContent
      data-slot="dropdown-menu-content"
      v-bind="{ ...$attrs, ...forwarded }"
      :class="[
        'fui-dropdown-menu-content z-50 data-open:animate-in data-closed:animate-out data-open:fade-in-0 data-closed:fade-out-0 data-open:zoom-in-95 data-closed:zoom-out-95 data-side-bottom:slide-in-from-top-2 data-side-left:slide-in-from-right-2 data-side-right:slide-in-from-left-2 data-side-top:slide-in-from-bottom-2 duration-100 max-h-(--reka-dropdown-menu-content-available-height) origin-(--reka-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto data-closed:overflow-hidden',
        props.class,
      ]"
    >
      <slot />
    </DropdownMenuContent>
  </DropdownMenuPortal>
</template>
```

`components/ui/dropdown-menu/DropdownMenuGroup.vue`

```vue
<script lang="ts">
/** Groups related entries of the dropdown menu. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuGroupProps } from 'reka-ui'
import { DropdownMenuGroup, useForwardProps } from 'reka-ui'

const props = defineProps<DropdownMenuGroupProps>()
const forwarded = useForwardProps(props)
</script>

<template>
  <DropdownMenuGroup data-slot="dropdown-menu-group" v-bind="forwarded">
    <slot />
  </DropdownMenuGroup>
</template>
```

`components/ui/dropdown-menu/DropdownMenuItem.vue`

```vue
<script lang="ts">
/** Holds one action the user can pick from the dropdown menu. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuItemProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { cva } from 'class-variance-authority'
import { reactiveOmit } from '@vueuse/core'
import { DropdownMenuItem, useForwardProps } from 'reka-ui'

const props = withDefaults(
  defineProps<
    DropdownMenuItemProps & {
      class?: HTMLAttributes['class']
      /** Indents the item to line up with items that show a check or icon. */
      inset?: boolean
      /** The item's intent: destructive marks an action that deletes or cannot be undone, such as removing an address. */
      color?: 'neutral' | 'destructive'
    }
  >(),
  {
    color: 'neutral',
  },
)

const delegatedProps = reactiveOmit(props, 'inset', 'color', 'class')

const forwardedProps = useForwardProps(delegatedProps)

const item = cva(
  'fui-dropdown-menu-item group/dropdown-menu-item relative cursor-default outline-hidden select-none data-disabled:pointer-events-none data-disabled:fui-disabled **:data-icon:pointer-events-none **:data-icon:shrink-0',
  {
    variants: {
      color: { destructive: 'fui-dropdown-menu-item-destructive' },
      pad: { default: 'fui-dropdown-menu-item-default', inset: 'fui-dropdown-menu-item-inset', indicator: 'fui-dropdown-menu-item-indicator' },
    },
    defaultVariants: { pad: 'default' },
  },
)
</script>

<template>
  <DropdownMenuItem
    data-slot="dropdown-menu-item"
    :data-inset="inset ? '' : undefined"
    :data-color="color"
    v-bind="forwardedProps"
    :class="[item({ color: props.color === 'destructive' ? 'destructive' : undefined, pad: props.inset ? 'inset' : 'default' }), props.class]"
  >
    <slot />
  </DropdownMenuItem>
</template>
```

`components/ui/dropdown-menu/DropdownMenuLabel.vue`

```vue
<script lang="ts">
/** Labels a group of entries in the dropdown menu. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuLabelProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { cva } from 'class-variance-authority'
import { DropdownMenuLabel, useForwardProps } from 'reka-ui'

const props = defineProps<
  DropdownMenuLabelProps & {
    class?: HTMLAttributes['class']
    /** Indents the label to line up with items that show a check or icon. */
    inset?: boolean
  }
>()

const delegatedProps = reactiveOmit(props, 'class', 'inset')
const forwardedProps = useForwardProps(delegatedProps)

const label = cva('fui-dropdown-menu-label', {
  variants: { pad: { default: 'fui-dropdown-menu-label-default', inset: 'fui-dropdown-menu-label-inset' } },
  defaultVariants: { pad: 'default' },
})
</script>

<template>
  <DropdownMenuLabel data-slot="dropdown-menu-label" :data-inset="inset ? '' : undefined" v-bind="forwardedProps" :class="[label({ pad: props.inset ? 'inset' : 'default' }), props.class]">
    <slot />
  </DropdownMenuLabel>
</template>
```

`components/ui/dropdown-menu/DropdownMenuPortal.vue`

```vue
<script lang="ts">
/** Places the menu content above the rest of the page. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuPortalProps } from 'reka-ui'
import { DropdownMenuPortal, useForwardProps } from 'reka-ui'

const props = defineProps<DropdownMenuPortalProps>()
const forwarded = useForwardProps(props)
</script>

<template>
  <DropdownMenuPortal v-bind="forwarded">
    <slot />
  </DropdownMenuPortal>
</template>
```

`components/ui/dropdown-menu/DropdownMenuRadioGroup.vue`

```vue
<script lang="ts">
/** Groups radio items so the user can pick exactly one. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuRadioGroupEmits, DropdownMenuRadioGroupProps } from 'reka-ui'
import { DropdownMenuRadioGroup, useForwardPropsEmits } from 'reka-ui'

const props = defineProps<DropdownMenuRadioGroupProps>()
const emits = defineEmits<DropdownMenuRadioGroupEmits>()

const forwarded = useForwardPropsEmits(props, emits)
</script>

<template>
  <DropdownMenuRadioGroup data-slot="dropdown-menu-radio-group" v-bind="forwarded">
    <slot />
  </DropdownMenuRadioGroup>
</template>
```

`components/ui/dropdown-menu/DropdownMenuRadioItem.vue`

```vue
<script lang="ts">
/** Lets the user choose one option from a group in the menu. */
export default {}
</script>

<script setup lang="ts">
import { CheckIcon } from '@lucide/vue'

import type { DropdownMenuRadioItemEmits, DropdownMenuRadioItemProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { DropdownMenuItemIndicator, DropdownMenuRadioItem, useForwardPropsEmits } from 'reka-ui'

const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes['class'] }>()

const emits = defineEmits<DropdownMenuRadioItemEmits>()

defineSlots<{
  /** Replaces the check icon shown on the chosen option. */
  'indicator-icon'?: () => unknown
  default?: () => unknown
}>()

const delegatedProps = reactiveOmit(props, 'class')

const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>

<template>
  <DropdownMenuRadioItem
    data-slot="dropdown-menu-radio-item"
    v-bind="forwarded"
    :class="[
      'fui-dropdown-menu-item fui-dropdown-menu-item-indicator relative cursor-default outline-hidden select-none data-disabled:pointer-events-none data-disabled:fui-disabled **:data-icon:pointer-events-none **:data-icon:shrink-0',
      props.class,
    ]"
  >
    <span class="pointer-events-none absolute inset-e-2 flex items-center justify-center" data-slot="dropdown-menu-radio-item-indicator">
      <DropdownMenuItemIndicator>
        <slot name="indicator-icon">
          <CheckIcon data-icon />
        </slot>
      </DropdownMenuItemIndicator>
    </span>
    <slot />
  </DropdownMenuRadioItem>
</template>
```

`components/ui/dropdown-menu/DropdownMenuSeparator.vue`

```vue
<script lang="ts">
/** Separates groups of entries in the dropdown menu. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuSeparatorProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { DropdownMenuSeparator, useForwardProps } from 'reka-ui'

const props = defineProps<
  DropdownMenuSeparatorProps & {
    class?: HTMLAttributes['class']
  }
>()

const delegatedProps = reactiveOmit(props, 'class')
const forwarded = useForwardProps(delegatedProps)
</script>

<template>
  <DropdownMenuSeparator data-slot="dropdown-menu-separator" v-bind="forwarded" :class="['fui-dropdown-menu-separator', props.class]" />
</template>
```

`components/ui/dropdown-menu/DropdownMenuShortcut.vue`

```vue
<script lang="ts">
/** Shows the keyboard shortcut for a menu item. */
export default {}
</script>

<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import { Primitive } from 'reka-ui'
import type { HTMLAttributes } from 'vue'

const props = withDefaults(
  defineProps<
    PrimitiveProps & {
      class?: HTMLAttributes['class']
    }
  >(),
  { as: 'span' },
)
</script>

<template>
  <Primitive :as="props.as" :as-child="props.asChild" data-slot="dropdown-menu-shortcut" :class="['fui-dropdown-menu-shortcut', props.class]">
    <slot />
  </Primitive>
</template>
```

`components/ui/dropdown-menu/DropdownMenuSub.vue`

```vue
<script lang="ts">
/** Groups a submenu trigger with the nested menu it opens. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuSubEmits, DropdownMenuSubProps } from 'reka-ui'
import { DropdownMenuSub, useForwardPropsEmits } from 'reka-ui'

const props = defineProps<DropdownMenuSubProps>()
const emits = defineEmits<DropdownMenuSubEmits>()

defineSlots<{
  /** Holds the submenu's trigger and content; gets whether the submenu is open. */
  default?: (props: { open: boolean }) => unknown
}>()

const forwarded = useForwardPropsEmits(props, emits)
</script>

<template>
  <DropdownMenuSub v-slot="slotProps" data-slot="dropdown-menu-sub" v-bind="forwarded">
    <slot v-bind="slotProps" />
  </DropdownMenuSub>
</template>
```

`components/ui/dropdown-menu/DropdownMenuSubContent.vue`

```vue
<script lang="ts">
/** Holds the entries the submenu shows while open. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuSubContentEmits, DropdownMenuSubContentProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { DropdownMenuSubContent, useForwardPropsEmits } from 'reka-ui'

const props = defineProps<DropdownMenuSubContentProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<DropdownMenuSubContentEmits>()

const delegatedProps = reactiveOmit(props, 'class')

const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>

<template>
  <DropdownMenuSubContent
    data-slot="dropdown-menu-sub-content"
    v-bind="forwarded"
    :class="[
      'fui-dropdown-menu-sub-content z-50 data-open:animate-in data-closed:animate-out data-open:fade-in-0 data-closed:fade-out-0 data-open:zoom-in-95 data-closed:zoom-out-95 data-side-bottom:slide-in-from-top-2 data-side-left:slide-in-from-right-2 data-side-right:slide-in-from-left-2 data-side-top:slide-in-from-bottom-2 duration-100 origin-(--reka-dropdown-menu-content-transform-origin) overflow-hidden',
      props.class,
    ]"
  >
    <slot />
  </DropdownMenuSubContent>
</template>
```

`components/ui/dropdown-menu/DropdownMenuSubTrigger.vue`

```vue
<script lang="ts">
/** Opens a submenu from an item of the dropdown menu. */
export default {}
</script>

<script setup lang="ts">
import { ChevronRightIcon } from '@lucide/vue'

import type { DropdownMenuSubTriggerProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { cva } from 'class-variance-authority'
import { reactiveOmit } from '@vueuse/core'
import { DropdownMenuSubTrigger, useForwardProps } from 'reka-ui'

const props = defineProps<
  DropdownMenuSubTriggerProps & {
    class?: HTMLAttributes['class']
    /** Indents the trigger to line up with items that show a check or icon. */
    inset?: boolean
  }
>()

const delegatedProps = reactiveOmit(props, 'class', 'inset')
const forwardedProps = useForwardProps(delegatedProps)

const subTrigger = cva('fui-dropdown-menu-sub-trigger cursor-default outline-hidden select-none **:data-icon:pointer-events-none **:data-icon:shrink-0', {
  variants: { pad: { default: 'fui-dropdown-menu-sub-trigger-default', inset: 'fui-dropdown-menu-sub-trigger-inset' } },
  defaultVariants: { pad: 'default' },
})
</script>

<template>
  <DropdownMenuSubTrigger
    data-slot="dropdown-menu-sub-trigger"
    :data-inset="inset ? '' : undefined"
    v-bind="forwardedProps"
    :class="[subTrigger({ pad: props.inset ? 'inset' : 'default' }), props.class]"
  >
    <slot />
    <ChevronRightIcon class="ms-auto rtl:rotate-180" data-icon />
  </DropdownMenuSubTrigger>
</template>
```

`components/ui/dropdown-menu/DropdownMenuTrigger.vue`

```vue
<script lang="ts">
/** Opens and closes the dropdown menu. */
export default {}
</script>

<script setup lang="ts">
import type { DropdownMenuTriggerProps } from 'reka-ui'
import { DropdownMenuTrigger, useForwardProps } from 'reka-ui'

const props = defineProps<DropdownMenuTriggerProps>()

const forwardedProps = useForwardProps(props)
</script>

<template>
  <DropdownMenuTrigger data-slot="dropdown-menu-trigger" v-bind="forwardedProps">
    <slot />
  </DropdownMenuTrigger>
</template>
```

## API of the items the example uses

### Button

[Full docs](https://ui.frontic.com/components/ui/button.md) · `npx @frontic/ui add button`

#### Button

Lets the user trigger an action, such as adding a product to the cart. Renders a `<button>`.

`data-slot="button"` · `Button.vue`

Styling: `button`, which extends [`action`](https://ui.frontic.com/DESIGN.md#action). Change it there and every part that extends it follows.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `asChild` | `boolean` | `false` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details. |
| `as` | `AsTag \| Component`: `ComponentOptions<any, any, any, ComputedOptions, MethodOptions, any, any, any, string, {}, {}, string, {}, {}, {}, string, ComponentProvideOptions> \| (props: any, ctx: Omit<{ attrs: Attrs; slots: Readonly<InternalSlots>; emit: (event: string, ...args: any[]) => void; expose: <Exposed extends Record<string, any> = Record<string, any>>(exposed?: Exposed \| undefined) => void; }, 'expose'>): any \| ComponentPublicInstanceConstructor<any, any, any, any, ComputedOptions, MethodOptions> \| 'a' \| 'button' \| 'div' \| 'form' \| 'h2' \| 'h3' \| 'img' \| 'input' \| 'label' \| 'li' \| 'nav' \| 'ol' \| 'p' \| 'span' \| 'svg' \| 'ul' \| 'template' \| {} & string` | `'button'` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `variant` | `'solid' \| 'outline' \| 'soft' \| 'ghost' \| 'link'` | `'solid'` | The visual style: a filled, outlined, tinted, background-free or text-link button. |
| `color` | `'neutral' \| 'primary' \| 'destructive' \| 'buy' \| 'checkout' \| 'inverse'` | `'primary'` | The colour role, e.g. primary for the brand colour, buy for add-to-cart, checkout for the checkout step, destructive for removing. |
| `size` | `'md' \| 'xs' \| 'sm' \| 'lg' \| 'icon-xs' \| 'icon-sm' \| 'icon-md' \| 'icon-lg'` | `'md'` | The button's height and padding; the `icon-*` sizes make a square, icon-only button. |
| `class` | `ClassValue` |  | Classes added to the part's own element, after its recipe classes. |

| Data attribute | Values | Description |
| --- | --- | --- |
| `data-color` | `'neutral' \| 'primary' \| 'destructive' \| 'buy' \| 'checkout' \| 'inverse'` | Carries the `color` prop. |
| `data-size` | `'md' \| 'xs' \| 'sm' \| 'lg' \| 'icon-xs' \| 'icon-sm' \| 'icon-md' \| 'icon-lg'` | Carries the `size` prop. |
| `data-variant` | `'solid' \| 'outline' \| 'soft' \| 'ghost' \| 'link'` | Carries the `variant` prop. |
