Skip to content

Menu API Reference

Props

PropTypeDefaultDescription
triggerTypeString'click'How the menu opens. Accepts 'click' or 'hover'.
offsetArray[0, 0.125][x, y] offset, expressed in REM units, applied to the computed position.
placementString'bottom'Preferred placement relative to the trigger (see list below).
closeOnOutsideClickBooleantrueClose when the user clicks outside the trigger/menu.
closeOnEscBooleantrueClose when the Escape key is pressed.
widthString/NumbernullExplicit menu width (CSS string or number in pixels).
matchTriggerWidthBooleantrueSync the menu width with the trigger when width is not provided.
menuContentClassArray[]Additional class names applied to the floating menu element.
disabledBooleanfalsePrevents the trigger from toggling the menu.
fixedXString''Override the computed left position (any CSS length/percentage).
fixedYString''Override the computed top position (any CSS length/percentage).
menuIdString''Adds deterministic IDs ({menuId}Trigger / {menuId}Content) for accessibility.
stopPropagationBooleantrueStops trigger click propagation; set false to allow parent listeners.

Placement Options

OMenu accepts: top, bottom, left, right, top-start, top-end, bottom-start, bottom-end, left-top, left-bottom, right-top, right-bottom. Collision detection can flip your preferred placement automatically to keep the menu inside the viewport.

Events

EventPayloadDescription
open-Fired after the menu opens.
close-Fired after the menu closes.

Slots

SlotDescription
triggerThe interactive element that toggles the menu. Receives { isOpen }.
contentThe floating menu content.

Exposed Methods

MethodDescription
openMenu()Programmatically open the menu.
closeMenu()Programmatically close the menu.
toggleMenu()Toggle the open/closed state.

Exposed Properties

PropertyTypeDescription
isOpenBooleanCurrent open state of the menu.
actualPlacementStringFinal placement after collision adjustments.

Features

Collision Detection

Viewport-aware logic flips or nudges the menu when the requested placement would overflow the visible window.

Hover Support

Set triggerType="hover" to open on mouse enter and close shortly after mouse leave, preventing accidental dismissals.

Responsive Positioning

The menu recalculates its position on window resize and scroll events to stay aligned with the trigger (unless fixedX/fixedY are provided).

Teleport

Menu content teleports to document.body to avoid stacking-context issues. Use menuContentClass to attach additional styling to the teleported element.

Example Usage

vue
<template>
  <OMenu
    ref="menuRef"
    trigger-type="click"
    placement="bottom-start"
    :width="280"
    :match-trigger-width="false"
    :menu-content-class="['elevation-panel']"
    @open="handleOpen"
    @close="handleClose"
  >
    <template #trigger>
      <button class="menu-trigger">
        Actions
        <span aria-hidden="true">▾</span>
      </button>
    </template>

    <template #content>
      <div class="menu-items">
        <button class="menu-item">Edit</button>
        <button class="menu-item">Duplicate</button>
        <button class="menu-item" disabled>Archive (disabled)</button>
      </div>
    </template>
  </OMenu>

  <button @click="menuRef?.openMenu()">Open programmatically</button>
  <button @click="menuRef?.closeMenu()">Close programmatically</button>
</template>

<script setup>
import { ref } from 'vue';

const menuRef = ref(null);

const handleOpen = () => {
  console.log('Menu opened');
};

const handleClose = () => {
  console.log('Menu closed');
};
</script>

Menu API Reference

Props

PropTypeDefaultDescription
triggerTypeString'click'How to open the menu. Options: 'click', 'hover'.
offsetArray[0, 0.125][x, y] offset from the trigger, measured in REM units.
placementString'bottom'Preferred placement relative to the trigger (see list below).
closeOnOutsideClickBooleantrueClose when a user clicks outside the trigger or content.
closeOnEscBooleantrueClose when the Escape key is pressed.
widthString/NumbernullExplicit menu width (CSS string or number in pixels).
matchTriggerWidthBooleantrueWhen true, auto-match the trigger width if width is unset.
menuContentClassArray[]Additional class names applied to the teleported menu element.
disabledBooleanfalsePrevent the trigger from opening the menu.
fixedXString''Overrides the calculated left position (any valid CSS length).
fixedYString''Overrides the calculated top position.
menuIdString''Adds IDs for trigger/content (e.g. {menuId}Trigger) to aid accessibility.
stopPropagationBooleantrueStops the trigger click from bubbling; set false to allow parent handlers.

Placement Options

OMenu accepts these placement strings: top, bottom, left, right, top-start, top-end, bottom-start, bottom-end, left-top, left-bottom, right-top, right-bottom. Collision detection can flip your requested placement automatically when the viewport would otherwise clip the menu.

Events

EventPayloadDescription
open-Emitted when menu opens
close-Emitted when menu closes

Slots

SlotDescription
triggerThe element that triggers the menu
contentThe menu content to display

Exposed Methods

The component exposes these methods via template refs:

MethodDescription
openMenu()Programmatically open the menu
closeMenu()Programmatically close the menu
toggleMenu()Toggle the menu open/closed state

Exposed Properties

PropertyTypeDescription
isOpenBooleanCurrent open/closed state of the menu
actualPlacementStringThe actual placement after collision detection

Features

Collision Detection

The menu automatically detects viewport boundaries and adjusts its position to prevent overflow. If the preferred placement would cause the menu to go outside the viewport, it will automatically flip to the opposite side.

Hover Support

When triggerType is set to 'hover', the menu opens on mouse enter and closes on mouse leave with a small delay to prevent accidental closing.

Responsive Positioning

The menu position updates automatically on window resize and scroll events to maintain proper positioning relative to the trigger element.

Teleport

Menu content teleports to document.body for consistent layering. Apply custom styles via menuContentClass if you need extra elevation, padding, or scroll tweaks.

Example Usage

vue
<template>
  <OMenu 
    ref="menuRef"
    trigger-type="click"
    placement="bottom-start"
    :width="300"
    :match-trigger-width="false"
    @open="handleOpen"
  >
    <template #trigger>
      <button>Open Menu</button>
    </template>
    <template #content>
      <div class="menu-items">
        <div class="menu-item">Item 1</div>
        <div class="menu-item">Item 2</div>
        <div class="menu-item">Item 3</div>
      </div>
    </template>
  </OMenu>
</template>

<script setup>
import { ref } from 'vue'

const menuRef = ref(null)

// Programmatic control
const openMenu = () => {
  menuRef.value.openMenu()
}

const handleOpen = () => {
  console.log('Menu opened')
}
</script>