PhiaUi.Components.DropdownMenu (phia_ui v0.1.17)

Copy Markdown View Source

Dropdown menu component with smart positioning, click-outside detection, and full WAI-ARIA keyboard navigation.

Requires the PhiaDropdownMenu JavaScript hook registered in app.js. The hook handles all interactivity: opening/closing the panel, focusing the first menu item on open, and full keyboard navigation (Arrow keys, Home, End, Escape, Tab).

Hook Registration

Copy the hook via mix phia.add dropdown_menu, then register it:

# assets/js/app.js
import PhiaDropdownMenu from "./hooks/dropdown_menu"

let liveSocket = new LiveSocket("/live", Socket, {
  hooks: { PhiaDropdownMenu }
})

Sub-components

FunctionElementPurpose
dropdown_menu/1divRelative container — JS hook anchor
dropdown_menu_trigger/1buttonToggle button with aria-haspopup/aria-expanded
dropdown_menu_content/1divFloating menu panel (role="menu")
dropdown_menu_item/1divClickable item (role="menuitem")
dropdown_menu_label/1divNon-interactive section heading
dropdown_menu_separator/1hrVisual divider between sections
dropdown_menu_group/1divLogical grouping wrapper
dropdown_menu_checkbox_item/1divToggle item (role="menuitemcheckbox")
dropdown_menu_radio_group/1divContainer for mutually exclusive items
dropdown_menu_radio_item/1divRadio item (role="menuitemradio")
dropdown_menu_shortcut/1spanRight-aligned keyboard shortcut hint

Basic Example — Account Menu

<.dropdown_menu id="user-menu">
  <.dropdown_menu_trigger>
    My Account
  </.dropdown_menu_trigger>
  <.dropdown_menu_content>
    <.dropdown_menu_label>My Account</.dropdown_menu_label>
    <.dropdown_menu_separator />
    <.dropdown_menu_group>
      <.dropdown_menu_item phx-click="goto_profile">
        Profile
        <.dropdown_menu_shortcut>P</.dropdown_menu_shortcut>
      </.dropdown_menu_item>
      <.dropdown_menu_item phx-click="goto_settings">
        Settings
        <.dropdown_menu_shortcut>S</.dropdown_menu_shortcut>
      </.dropdown_menu_item>
    </.dropdown_menu_group>
    <.dropdown_menu_separator />
    <.dropdown_menu_item variant="destructive" phx-click="logout">
      Log out
    </.dropdown_menu_item>
  </.dropdown_menu_content>
</.dropdown_menu>

Checkbox Items Example — View Options

<.dropdown_menu id="view-menu">
  <.dropdown_menu_trigger>View</.dropdown_menu_trigger>
  <.dropdown_menu_content>
    <.dropdown_menu_label>Appearance</.dropdown_menu_label>
    <.dropdown_menu_separator />
    <.dropdown_menu_checkbox_item
      checked={@show_toolbar}
      phx-click="toggle_toolbar">
      Show Toolbar
    </.dropdown_menu_checkbox_item>
    <.dropdown_menu_checkbox_item
      checked={@show_statusbar}
      phx-click="toggle_statusbar">
      Show Status Bar
    </.dropdown_menu_checkbox_item>
  </.dropdown_menu_content>
</.dropdown_menu>

Radio Items Example — Theme Selector

<.dropdown_menu id="theme-menu">
  <.dropdown_menu_trigger>Theme</.dropdown_menu_trigger>
  <.dropdown_menu_content>
    <.dropdown_menu_radio_group>
      <.dropdown_menu_radio_item
        :for={theme <- ~w(Light Dark System)}
        checked={theme == @current_theme}
        phx-click="set_theme"
        phx-value-theme={theme}>
        {theme}
      </.dropdown_menu_radio_item>
    </.dropdown_menu_radio_group>
  </.dropdown_menu_content>
</.dropdown_menu>

Keyboard Navigation

The PhiaDropdownMenu hook provides full WAI-ARIA keyboard support:

  • Enter / Space — opens the menu when trigger is focused
  • ArrowDown / ArrowUp — moves focus between items
  • Home / End — jumps to first / last item
  • Escape — closes the menu and returns focus to the trigger
  • Tab — closes the menu naturally (focus leaves the component)

Accessibility

  • Trigger has aria-haspopup="menu" and aria-expanded (toggled by hook)
  • Menu panel has role="menu" and aria-orientation="vertical"
  • Each item has role="menuitem" (or menuitemcheckbox / menuitemradio)
  • Disabled items use aria-disabled="true" and pointer-events-none rather than the HTML disabled attribute, because disabled removes items from the accessibility tree and breaks keyboard navigation

Summary

Functions

Renders the relative-positioned container that anchors the JS hook.

Renders a toggleable menu item with a checkmark indicator.

Renders the floating menu panel.

Wraps a logical group of menu items together.

Renders a clickable menu item with role="menuitem".

Renders a non-interactive section heading inside the menu.

Wraps a set of mutually exclusive dropdown_menu_radio_item/1 components.

Renders a radio-style menu item with a filled bullet indicator.

Renders a horizontal visual separator between groups of menu items.

Renders a right-aligned keyboard shortcut hint inside a menu item.

Wraps a submenu — a trigger item that reveals a nested menu panel.

Renders the submenu content panel positioned to the right of the trigger.

Renders an item that opens a submenu on hover or click.

Renders the trigger button that opens and closes the dropdown menu.

Functions