Returnless UI

Dropdown Menu

Based on: Reka Dropdown Menu

Displays a menu to the user—such as a set of actions or functions—triggered by a button.

  • Can be controlled or uncontrolled.
  • Supports submenus with configurable reading direction.
  • Supports items, labels, groups of items.
  • Supports checkable items (single or multiple) with optional indeterminate state.
  • Supports modal and non-modal modes.
  • Customize side, alignment, offsets, collision handling.
  • Optionally render a pointing arrow.
  • Focus is fully managed.
  • Full keyboard navigation.
  • Typeahead support.
  • Dismissing and layering behavior is highly customizable.

DropdownMenu

Props
defaultOpen?:
boolean
Defaults to unknown
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
Defaults to unknown
The controlled open state of the menu. Can be used as `v-model:open`.
dir?:
Direction$4
Defaults to unknown
The reading direction of the combobox when applicable. If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode.
modal?:
boolean
Defaults to unknown
The modality of the dropdown menu. When set to `true`, interaction with outside elements will be disabled and only menu content will be visible to screen readers.
Events
update:open:
[payload: boolean]

DropdownMenuContent

Props
forceMount?:
boolean
Defaults to unknown
Used to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries.
align?:
"start" | "end" | "center"
Defaults to unknown
The preferred alignment against the trigger. May change when collisions occur.
asChild?:
boolean
Defaults to unknown
Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
as?:
AsTag | Component
Defaults to unknown
The element or component this component should render as. Can be overwritten by `asChild`.
side?:
"top" | "right" | "bottom" | "left"
Defaults to unknown
The preferred side of the trigger to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled.
sideOffset?:
number
Defaults to 6
The distance in pixels from the trigger.
sideFlip?:
boolean
Defaults to unknown
Flip to the opposite side when colliding with boundary.
alignOffset?:
number
Defaults to unknown
An offset in pixels from the `start` or `end` alignment options.
alignFlip?:
boolean
Defaults to unknown
Flip alignment when colliding with boundary. May only occur when `prioritizePosition` is true.
avoidCollisions?:
boolean
Defaults to unknown
When `true`, overrides the side and align preferences to prevent collisions with boundary edges.
collisionBoundary?:
Element | (Element | null)[] | null
Defaults to unknown
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>>
Defaults to unknown
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
Defaults to unknown
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.
sticky?:
"partial" | "always"
Defaults to unknown
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
Defaults to unknown
Whether to hide the content when the trigger becomes fully occluded.
positionStrategy?:
"fixed" | "absolute"
Defaults to unknown
The type of CSS position property to use.
updatePositionStrategy?:
"always" | "optimized"
Defaults to unknown
Strategy to update the position of the floating element on every animation frame.
disableUpdateOnLayoutShift?:
boolean
Defaults to unknown
Whether to disable the update position for the content when the layout shifted.
prioritizePosition?:
boolean
Defaults to unknown
Force content to be position within the viewport. Might overlap the reference element, which may not be desired.
reference?:
ReferenceElement
Defaults to unknown
The custom element or virtual element that will be set as the reference to position the floating element. If provided, it will replace the default anchor element.
loop?:
boolean
Defaults to unknown
When `true`, keyboard navigation will loop from last item to first, and vice versa.
Events
escapeKeyDown:
[event: KeyboardEvent]
pointerDownOutside:
[event: PointerDownOutsideEvent]
focusOutside:
[event: FocusOutsideEvent]
interactOutside:
[event: PointerDownOutsideEvent | FocusOutsideEvent]
closeAutoFocus:
[event: Event]

DropdownMenuItem

Props
disabled?:
boolean
Defaults to unknown
When `true`, prevents the user from interacting with the item.
textValue?:
string
Defaults to unknown
Optional text used for typeahead purposes. By default the typeahead behavior will use the `.textContent` of the item. <br> Use this when the content is complex, or you have non-textual content inside.
asChild?:
boolean
Defaults to unknown
Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
as?:
AsTag | Component
Defaults to unknown
The element or component this component should render as. Can be overwritten by `asChild`.
icon?:
FunctionalComponent<HTMLAttributes & VNodeProps, {}, any, {}> | null
Defaults to unknown
variant?:
"default" | "destructive"
Defaults to unknown

DropdownMenuSeparator

Props
asChild?:
boolean
Defaults to unknown
Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
as?:
AsTag | Component
Defaults to unknown
The element or component this component should render as. Can be overwritten by `asChild`.

DropdownMenuTrigger

Props
disabled?:
boolean
Defaults to unknown
When `true`, prevents the user from interacting with item
asChild?:
boolean
Defaults to unknown
Change the default rendered element for the one passed as a child, merging their props and behavior. Read our [Composition](https://www.reka-ui.com/docs/guides/composition) guide for more details.
as?:
AsTag | Component
Defaults to unknown
The element or component this component should render as. Can be overwritten by `asChild`.

Usage

[]
js
<script lang="ts" setup>
import {
  Button,
  DropdownMenu,
  DropdownMenuItem,
  DropdownMenuTrigger,
  DropdownMenuContent,
  DropdownMenuSeparator,
} from '@returnless/focus-ui'; 
import { TrashIcon, PencilIcon, ArrowUpTrayIcon, ArrowDownTrayIcon } from '@heroicons/vue/16/solid';
</script>

<template>
  <DropdownMenu>
    <DropdownMenuTrigger>
      <Button disclosure variant="ghost">Action trigger</Button>
    </DropdownMenuTrigger>
    <DropdownMenuContent>
      <DropdownMenuItem :icon="ArrowDownTrayIcon">
        Import file
      </DropdownMenuItem>
      <DropdownMenuItem :icon="ArrowUpTrayIcon">
        Export file
      </DropdownMenuItem>
      <DropdownMenuSeparator />
      <DropdownMenuItem :icon="PencilIcon">
        Edit
      </DropdownMenuItem>
      <DropdownMenuItem :icon="TrashIcon" variant="destructive">
        Delete
      </DropdownMenuItem>
      <DropdownMenuCheckboxItem v-model="checkedItems" value="1">
        Checkable item
      </DropdownMenuCheckboxItem>
      <DropdownMenuCheckboxItem v-model="checkedItems" value="2">
        Checkable item
      </DropdownMenuCheckboxItem>
    </DropdownMenuContent>
  </DropdownMenu>
</template>

Best practices

Dropdown Menu's should:

  • Be used for secondary or less important information and actions since they're hidden until users expose them by opening a popover
  • Contain actions that are related to each other

Content guidelines

Each item in an action list should be clear and predictable. Users should be able to anticipate what will happen when they click on an action.

Each item in an action list should always lead with a strong verb that encourages action. To provide enough context use the {verb}+{noun} format unless the action is clear with a single verb.

Each item in an action list should be scannable avoiding unnecessary words and articles such as "the", "an", or "a".

Accessibility

Items in an action list are organized as list items (<li>) in an unordered list (<ul>) and are conveyed as a group of related elements to assistive technology users. Each item is implemented as a button.