Skip to content

ODropdown ​

ODropdown anchors reusable popup content to a native button without imposing selection state on that content.

Usage ​

Step by step ​

  1. Import ODropdown from the ooko-ui/dropdown public subpath.
  2. Put the accessible trigger label in the default slot; the dropdown adds a Lucide direction icon from placement.
  3. Put content matching popupRole in the content slot and use its close function after an action.

Example ​

The rendered example and its source come from the same Vue single-file component.

Interactive playground ​

Change the trigger label, popup role, placement, controlled open state, and disabled state. The preview updates immediately.

Props ​

PropTypeDefaultDescription
openbooleanfalseControls the popup when provided; omit it to let the dropdown manage its own state.
triggerbooleantrueRenders the built-in button trigger. Set to false when an owning control opens the popup itself.
disabledbooleanfalsePrevents the trigger from opening the popup.
placementODropdownPlacement"bottom-start"Positions the popup relative to its trigger.
popupRoleODropdownPopupRole"menu"Declares the popup's accessible role.
popupLabelstringundefinedProvides the popup's accessible name instead of deriving it from the trigger.
glassbooleanfalseUses a translucent, blurred popup with a thin border. Defaults to the app's glass option.

Events ​

EventPayloadDescription
update:openbooleanRequests or reports a change to the popup's open state.

Slots ​

SlotPropsDescription
defaultnoneProvides the trigger label displayed before the automatic placement icon.
triggernoneReplaces the complete trigger content, including the automatic placement icon.
contentODropdownContentSlotPropsProvides the popup content and an explicit close action.
TypeDefinition
ODropdownContentSlotPropsinterface ODropdownContentSlotProps { /** Closes the popup and optionally restores focus to its trigger. */ close: (restoreFocus?: boolean) => void; }
ODropdownPlacementtype ODropdownPlacement = "bottom-start" | "bottom-end" | "top-start" | "top-end" | "right-start" | "right-end" | "left-start" | "left-end";
ODropdownPopupRoletype ODropdownPopupRole = "dialog" | "menu";

CSS custom properties ​

Custom propertyDefaultDescription
--o-dropdown-panel-min-width10remSets the popup's minimum width before viewport constraints apply.
--o-dropdown-panel-paddingvar(--o-space-2)Sets the popup's internal spacing.
--o-dropdown-panel-border1px solid var(--o-border-color-subtle)Sets the popup border shorthand.
--o-dropdown-panel-radiusvar(--o-radius-surface)Sets the popup corner radius.
--o-dropdown-panel-backgroundvar(--o-background-glass-strong)Sets the popup background.
--o-dropdown-panel-z-index10Sets the popup stacking order.
--o-dropdown-glass-backgroundvar(--o-background-glass)Sets the translucent popup background of a glass dropdown or select.
--o-dropdown-glass-border1px solid var(--o-border-glass)Sets the popup border shorthand of a glass dropdown or select.
--o-dropdown-glass-backdrop-filtervar(--o-backdrop-filter-glass)Sets the filter applied to the content behind a glass popup.

Override example ​

css
:root {
  --o-dropdown-panel-min-width: 14rem;
  --o-dropdown-panel-radius: var(--o-radius-round);
}

Accessibility ​

The trigger is a native button named by the default slot. Its automatic Lucide icon is decorative and hidden from assistive technologies. The button exposes the popup role, expanded state and controlled panel. Opening focuses the first focusable element in the popup, or the popup itself when it contains none. Arrow Up, Arrow Down, Home and End move through menu items. Arrow Right opens a right-placed submenu and Arrow Left closes it; the directions reverse for a left-placed submenu. Escape closes the popup and restores trigger focus; moving focus or clicking outside closes it without stealing focus. Disabled dropdowns use the native disabled state.

Consumers must match popup content to popupRole: use menuitem descendants and menu keyboard behavior for menus, or provide appropriate dialog content for dialogs. Nested dropdowns can use a side placement for submenus.

Behavior and edge cases ​

Without open, the dropdown owns its open state. Providing open makes it controlled: interactions emit update:open, and the parent must update the value. The content slot's close action closes explicitly and restores focus by default. Bottom, top, left and right placements render the matching Lucide chevron after the default slot. Providing the optional trigger slot replaces both the default content and automatic icon, allowing complete trigger customization. Native attributes and listeners are forwarded to the trigger. The component renders deterministically during SSR and attaches positioning and dismissal behavior only on the client.

glass draws a translucent, blurred popup with a thin border through the --o-dropdown-glass-* properties, matching glass dialogs and cards; it follows the app's glass option unless set on the dropdown. Browsers without backdrop-filter show the translucent popup without blur.

vue
<ODropdown>
  <template #trigger>
    <span class="custom-trigger">Open actions</span>
  </template>
  <template #content="{ close }">
    <button role="menuitem" type="button" @click="close()">Archive</button>
  </template>
</ODropdown>