PhoenixKitWeb.Components.Core.TableRowMenu (phoenix_kit v2.40.1)

Copy Markdown View Source

Dropdown action menu for table rows.

Provides a compact "⋮" trigger button that opens a floating menu with action items. Uses position: fixed via the RowMenu JS hook to escape overflow-clip table containers — a common DaisyUI issue when dropdowns are nested inside tables.

The menu is automatically positioned to stay within the viewport: it opens below the trigger by default, flips above if there's no space below, and aligns to the right edge of the trigger (shifting left if that would clip off-screen).

Works on mobile and desktop. On mobile the menu is full-width clamped to viewport.

Right-click (opt-in)

An element flagged data-row-menu-context opens the menu rendered INSIDE it at the pointer:

<.table_default_row data-row-menu-context>
  …
  <.table_row_menu id={"item-menu-#{item.uuid}"}> … </.table_row_menu>
</.table_default_row>

A flag, not the menu's id, because the row element is usually rendered by a shared table component that never sees the id its caller built for the menu in the actions slot — so the row says "right-click me" and the menu is found within it.

Put it on the whole row, or on one cell to confine the gesture. Nested rows resolve to the innermost one (Element.closest/1), and a menu belonging to a nested row is never opened by a right-click on its parent. A right-click that matches nothing — page background, a header, a row whose menu is behind an :if and so absent from the DOM — leaves the browser's own menu alone; suppressing it with nothing to show in its place would cost the user Copy and Inspect for no gain. Omit the attribute to disable the gesture, which is how a setting turns it off.

Not Core.ContextMenu, deliberately: that component's single menu element serves every row, so it stamps phx-value-* onto its items and an item's navigate/href cannot vary by row. This component already renders one menu per row, so per-row destinations keep working and no item is written twice. Use Core.ContextMenu when the rows have no ⋮ menu of their own (a tree, a grid of tiles) — the two cost the same right-click.

Components

Example

<.table_row_menu id={"menu-#{user.uuid}"}>
  <.table_row_menu_link
    navigate={Routes.path("/admin/users/view/#{user.uuid}")}
    icon="hero-eye"
    label={gettext("View")}
  />
  <.table_row_menu_link
    navigate={Routes.path("/admin/users/edit/#{user.uuid}")}
    icon="hero-pencil"
    label={gettext("Edit")}
    variant="secondary"
  />
  <.table_row_menu_divider />
  <.table_row_menu_button
    phx-click="delete"
    phx-value-id={user.uuid}
    icon="hero-trash"
    label={gettext("Delete")}
    variant="error"
  />
</.table_row_menu>

Summary

Functions

Renders the dropdown trigger and menu container.

Renders an action button item inside the menu.

Renders a visual separator between menu item groups.

Renders a navigation link item inside the menu.

Functions

table_row_menu(assigns)

Renders the dropdown trigger and menu container.

Attributes

  • id - Unique element ID (required). Used by the JS hook.

  • label - Accessible label for the trigger button (optional, default: "Actions")

  • mode - Display mode (optional, default: "dropdown"):

    • "dropdown" — always show the ⋮ dropdown menu (original behavior)
    • "inline" — always show actions as inline buttons (no dropdown)
    • "auto" — inline buttons on md+ screens, dropdown on mobile
  • class - Additional CSS classes for the wrapper (optional)

  • trigger_class - Additional CSS classes appended to the trigger button (optional)

  • trigger_size - Size of the ⋮ trigger (optional, default: "xs"):

    • "xs" — 24px, compact (table rows; the original size)
    • "sm" — 32px
    • "md" — 40px, a comfortable touch target

    Pass this instead of a btn-sm in trigger_class: the trigger's size class is replaced, not appended, because in the built CSS .btn-xs sorts after .btn-sm and would win if both were present.

Slots

  • inner_block - Menu items (use table_row_menu_link, table_row_menu_button, table_row_menu_divider)

Attributes

  • id (:string) (required)
  • label (:string) - Defaults to "Actions".
  • mode (:string) - Defaults to "dropdown". Must be one of "dropdown", "inline", or "auto".
  • class (:string) - Defaults to nil.
  • trigger_class (:string) - Defaults to nil.
  • trigger_size (:string) - Defaults to "xs". Must be one of "xs", "sm", or "md".

Slots

  • inner_block (required)

table_row_menu_button(assigns)

Renders an action button item inside the menu.

Attributes

  • icon - Heroicon name, e.g. "hero-trash" (optional)
  • label - Item label text (required)
  • variant - Color variant: "default", "primary", "secondary", "info", "success", "warning", "error" (optional, default: "default")
  • rest - Additional HTML attributes (phx-click, phx-value-*, data-confirm, etc.)

Attributes

  • icon (:string) - Defaults to nil.
  • label (:string) (required)
  • variant (:string) - Defaults to "default".
  • Global attributes are accepted.

table_row_menu_divider(assigns)

Renders a visual separator between menu item groups.

table_row_menu_link(assigns)

Renders a navigation link item inside the menu.

Attributes

  • navigate - LiveView navigate path (optional)
  • patch - LiveView patch path for same-LiveView navigation (optional)
  • href - Regular href (optional)
  • icon - Heroicon name, e.g. "hero-eye" (optional)
  • label - Item label text (required)
  • variant - Color variant: "default", "primary", "secondary", "info", "success", "warning", "error" (optional, default: "default")
  • rest - Additional HTML attributes passed to the <a> element. Includes target and rel (e.g. target="_blank" rel="noopener noreferrer" for external links opening in a new tab), plus method, csrf_token and data-confirm so an item can drive a non-GET action. Anything that rewrites the session — signing in as another user, for one — has to leave LiveView and go through a real request, which href + method="post" does; a phx-click cannot, because it never touches the session cookie.

Attributes

  • navigate (:string) - Defaults to nil.
  • patch (:string) - push_patch destination (same-LiveView navigation). Defaults to nil.
  • href (:string) - Defaults to nil.
  • icon (:string) - Defaults to nil.
  • label (:string) (required)
  • variant (:string) - Defaults to "default".
  • Global attributes are accepted. Supports all globals plus: ["target", "rel", "method", "csrf_token", "data-confirm"].