suiss/ui
  • Docs
  • Components
  • Patterns
  • Interactions
  • Charts
  • Blocks
GitHubGet started
DocsComponentsPatternsInteractionsChartsBlocks
Patterns19
  • Overview
  • Action Bar
  • Action Menu
  • App Shell
  • Command Palette
  • Confirm
  • Context Actions
  • Date Picker
  • Flyout
  • Modal
  • Navbar
  • Paged List
  • Panel
  • Picker
  • Preview
  • Search Picker
  • Segment Picker
  • Split View
  • Table List
  • Trail

suiss/ui · Pattern

Action Menu

A list of actions that opens as a dropdown menu on desktop and an action sheet on mobile.

Action Menu is an open-source pattern from suiss/ui for React. The @esuiss/ui CLI copies its source into your project, so you own the code.

import {
  ActionMenu,
  ActionMenuContent,
  ActionMenuItem,
  ActionMenuLabel,
  ActionMenuSeparator,
  ActionMenuTrigger,
} from "@/components/patterns/action-menu"
import { Button } from "@/components/ui/button"

export default function ActionMenuDemo() {
  return (
    <div className="flex min-h-svh items-center justify-center">
      <ActionMenu>
        <ActionMenuTrigger render={<Button variant="outline" />}>
          Order actions
        </ActionMenuTrigger>
        <ActionMenuContent>
          <ActionMenuLabel>Order #1042</ActionMenuLabel>
          <ActionMenuItem>Edit</ActionMenuItem>
          <ActionMenuItem>Duplicate</ActionMenuItem>
          <ActionMenuItem>Share</ActionMenuItem>
          <ActionMenuSeparator />
          <ActionMenuItem variant="destructive">Delete</ActionMenuItem>
        </ActionMenuContent>
      </ActionMenu>
    </div>
  )
}

ActionMenu renders a DropdownMenu on desktop and an AlertSheet below the 48rem breakpoint (useIsMobile). Each part switches to its matching component: items become DropdownMenuItems or AlertSheetActions, and the label becomes a menu label or the sheet title. On mobile, the content wraps the items in a grouped card and appends a Cancel button.

Use it for a short set of actions on a single object, such as editing, sharing or deleting a record, where an iOS-style action sheet suits touch screens.

Installation

CLI

$ pnpm dlx shadcn@latest add @esuiss/action-menu

Works in any project with a components.json. See Installation for the one-line registry setup. Or use the suiss/ui CLI:

$ pnpm dlx @esuiss/ui@latest add patterns action-menu

Manual

  1. Add the pieces it builds on: Alert Sheet, Dropdown Menu, use-mobile.

  2. Copy the source into components/patterns/action-menu.tsx:

components/patterns/action-menu.tsx
"use client"

import * as React from "react"

import {
  AlertSheet,
  AlertSheetAction,
  AlertSheetCancel,
  AlertSheetContent,
  AlertSheetGroup,
  AlertSheetHeader,
  AlertSheetTitle,
  AlertSheetTrigger,
} from "@/components/ui/alert-sheet"
import {
  DropdownMenu,
  1. Update the import paths to match your project.

Usage

import { ActionMenu, ActionMenuTrigger, ActionMenuContent, ActionMenuLabel, ActionMenuItem, ActionMenuSeparator } from "@/components/patterns/action-menu"
<div className="flex min-h-svh items-center justify-center">
  <ActionMenu>
    <ActionMenuTrigger render={<Button variant="outline" />}>
      Order actions
    </ActionMenuTrigger>
    <ActionMenuContent>
      <ActionMenuLabel>Order #1042</ActionMenuLabel>
      <ActionMenuItem>Edit</ActionMenuItem>
      <ActionMenuItem>Duplicate</ActionMenuItem>
      <ActionMenuItem>Share</ActionMenuItem>
      <ActionMenuSeparator />
      <ActionMenuItem variant="destructive">Delete</ActionMenuItem>
    </ActionMenuContent>
  </ActionMenu>
</div>
<div className="flex min-h-svh items-center justify-center">
  <ActionMenu>
    <Button variant="outline">Order actions</Button>
    <ActionMenuContent>
      <ActionMenuLabel>Order #1042</ActionMenuLabel>
      <ActionMenuItem>Edit</ActionMenuItem>
      <ActionMenuItem>Duplicate</ActionMenuItem>
      <ActionMenuItem>Share</ActionMenuItem>
      <ActionMenuSeparator />
      <ActionMenuItem variant="destructive">Delete</ActionMenuItem>
    </ActionMenuContent>
  </ActionMenu>
</div>

Pass render to ActionMenuTrigger to use your own button, for example a Button with variant="outline". open, defaultOpen and onOpenChange work on both layouts, so the menu can be controlled or uncontrolled. align, alignOffset, side and sideOffset on ActionMenuContent position the desktop popup and are ignored on mobile.

Examples

With icons

Places an icon before every action, including a destructive Delete item.

import {
  CopyIcon,
  PencilSimpleIcon,
  ShareIcon,
  TrashIcon,
} from "@phosphor-icons/react"
import {
  ActionMenu,
  ActionMenuContent,
  ActionMenuItem,
  ActionMenuSeparator,
  ActionMenuTrigger,
} from "@/components/patterns/action-menu"
import { Button } from "@/components/ui/button"

export default function ActionMenuWithIcons() {
  return (
    <div className="flex min-h-svh items-center justify-center">
      <ActionMenu>
        <ActionMenuTrigger render={<Button variant="outline" />}>
          Order actions
        </ActionMenuTrigger>
        <ActionMenuContent>
          <ActionMenuItem>
            <PencilSimpleIcon />
            Edit
          </ActionMenuItem>
          <ActionMenuItem>
            <CopyIcon />
            Duplicate
          </ActionMenuItem>
          <ActionMenuItem>
            <ShareIcon />
            Share
          </ActionMenuItem>
          <ActionMenuSeparator />
          <ActionMenuItem variant="destructive">
            <TrashIcon />
            Delete
          </ActionMenuItem>
        </ActionMenuContent>
      </ActionMenu>
    </div>
  )
}

Not dismissible

Sets dismissible to false so the mobile sheet closes only through an action or Cancel.

import {
  ActionMenu,
  ActionMenuContent,
  ActionMenuItem,
  ActionMenuLabel,
  ActionMenuSeparator,
  ActionMenuTrigger,
} from "@/components/patterns/action-menu"
import { Button } from "@/components/ui/button"

export default function ActionMenuNotDismissible() {
  return (
    <div className="flex min-h-svh items-center justify-center">
      <ActionMenu dismissible={false}>
        <ActionMenuTrigger render={<Button variant="outline" />}>
          Order actions
        </ActionMenuTrigger>
        <ActionMenuContent>
          <ActionMenuLabel>Order #1042</ActionMenuLabel>
          <ActionMenuItem>Edit</ActionMenuItem>
          <ActionMenuItem>Duplicate</ActionMenuItem>
          <ActionMenuItem>Share</ActionMenuItem>
          <ActionMenuSeparator />
          <ActionMenuItem variant="destructive">Delete</ActionMenuItem>
        </ActionMenuContent>
      </ActionMenu>
    </div>
  )
}

API Reference

Anatomy6 parts
<ActionMenu>
<ActionMenuTrigger />
<ActionMenuContent>
<ActionMenuLabel />
<ActionMenuItem />
<ActionMenuSeparator />
</ActionMenuContent>
</ActionMenu>
01

ActionMenu

The root that renders a DropdownMenu on desktop and an AlertSheet on mobile.

PropTypeDefaultDescription
onOpenChange(open: boolean) => void-Called when the menu or sheet opens or closes.
dismissiblebooleantrueWhen true, the mobile sheet closes on an outside press; when false, it uses an alert dialog that closes only through an action or Cancel.

Also accepts the props of React.ComponentProps<typeof DropdownMenu>.

02

ActionMenuTrigger

The button that opens the menu or sheet.

PropTypeDefaultDescription
renderReact.ReactElement-Replaces the default button element with your own element, such as a Button.

Also accepts the props of React.ButtonHTMLAttributes<HTMLButtonElement>.

03

ActionMenuContent

The popup holding the actions; on mobile it adds a Cancel button below them.

PropTypeDefaultDescription
cancelLabelstring"Cancel"Text of the Cancel button shown below the actions on mobile.

Also accepts the props of React.HTMLAttributes<HTMLElement>, React.ComponentProps<typeof DropdownMenuContent>.

04

ActionMenuLabel

A non-interactive heading; a menu label on desktop and the sheet title on mobile.

Also accepts the props of React.HTMLAttributes<HTMLElement>.

05

ActionMenuItem

An actionable entry that closes the menu when chosen.

PropTypeDefaultDescription
variant"default" | "destructive"-Use destructive to style the item as a destructive action.
disabledboolean-Prevents the item from being chosen.

Also accepts the props of React.HTMLAttributes<HTMLElement>.

On the aria base, respond to the item with onAction.

06

ActionMenuSeparator

A divider between groups of items, rendered on desktop only.

Also accepts the props of React.HTMLAttributes<HTMLElement>.

Accessibility

  • On desktop the popup has the menu role and each item has the menuitem role.
  • ArrowDown from the trigger opens the menu and focuses the first item; arrow keys move between items and Enter runs the focused one.
  • Escape closes the menu and returns focus to the trigger.

Notes

Parts carry data-slot values action-menu, action-menu-trigger, action-menu-content, action-menu-label, action-menu-item and action-menu-separator. ActionMenuSeparator renders nothing on mobile; the sheet groups items in a single card instead.

NextApp ShellPreviousAction Bar

On this page

  1. 01Installation
    • CLI
    • Manual
  2. 02Usage
  3. 03Examples
    • With icons
    • Not dismissible
  4. 04API Reference
    • ActionMenu
    • ActionMenuTrigger
    • ActionMenuContent
    • ActionMenuLabel
    • ActionMenuItem
    • ActionMenuSeparator
  5. 05Accessibility
  6. 06Notes