Skip to content

ActionPanel

ActionPanel is a presentational card component for rendering a vertical list of actions (icon + label). It is designed for ERP detail pages and side panels where available actions are often backend-driven.

Import

tsx
import { ActionPanel } from "@tailor-platform/app-shell";

Basic Usage

tsx
<ActionPanel
  title="Actions"
  actions={[
    {
      key: "create-invoice",
      label: "Create new sales invoice",
      icon: <ReceiptIcon />,
      onClick: () => openCreateInvoiceModal(),
    },
    {
      key: "view-docs",
      label: "View documentation",
      icon: <ExternalLinkIcon />,
      onClick: () => window.open("/docs", "_blank", "noopener,noreferrer"),
    },
  ]}
/>

Props

ActionPanel Props

PropTypeDefaultDescription
titlestringRequiredCard title (for example, "Actions")
actionsActionItem[]RequiredList of actions to render
classNamestring-Additional CSS classes for the card root

ActionItem

PropertyTypeDefaultDescription
keystringRequiredUnique key for stable rendering
labelstringRequiredAction label shown to users
iconReactNodeRequiredIcon rendered in a fixed 16px slot
onClick() => void | Promise<void>-Click handler for the action
disabledbooleanfalseDisables interaction and applies disabled styling
loadingbooleanfalseShows spinner, disables interaction, sets busy UI

Behavior

  • Rows are rendered as <button type="button"> elements.
  • disabled or loading makes the row non-interactive.
  • When loading is true, the icon slot renders a spinner without shifting layout.
  • Empty actions show a built-in fallback message: No actions available.

With Loading State

Use parent state to control which row is loading:

tsx
const [loadingKey, setLoadingKey] = useState<string | null>(null);

const handleConfirm = async () => {
  setLoadingKey("confirm");
  try {
    await confirmOrder(orderId);
  } finally {
    setLoadingKey(null);
  }
};

<ActionPanel
  title="Actions"
  actions={[
    {
      key: "confirm",
      label: "Confirm order",
      icon: <CheckIcon />,
      onClick: handleConfirm,
      loading: loadingKey === "confirm",
    },
  ]}
/>;

CommandPalette Integration

ActionPanel automatically registers its enabled actions to the CommandPalette. Actions that are not disabled, not loading, and have an onClick handler are registered under the panel's title as the group name. Registration is cleaned up when the component unmounts.

This means users can discover and trigger any visible ActionPanel action via Cmd+K / Ctrl+K without any additional setup.

tsx
// Actions in this panel will automatically appear in the CommandPalette
<ActionPanel
  title="Order Actions"
  actions={[
    { key: "confirm", label: "Confirm order", icon: <CheckIcon />, onClick: handleConfirm },
    { key: "cancel", label: "Cancel order", icon: <XIcon />, onClick: handleCancel },
  ]}
/>

Note: ActionPanel must be rendered inside AppShell (which provides the required CommandPaletteProvider). Rendering it outside that tree will throw.

Backend-Driven Pattern

In ERP apps, the backend often decides which actions are available for a document. A common setup:

  1. Backend returns document data and available action keys.
  2. Frontend maps each key to a registry entry (label, icon, execute).
  3. Page builds ActionItem[] and wires onClick.
  4. Page controls loading per key and passes it to ActionPanel.

This keeps ActionPanel simple and reusable across entity types.

Accessibility

  • Action list uses role="list" and each row wrapper uses role="listitem".
  • Buttons are keyboard accessible and include focus-visible states.
  • Loading rows set aria-busy="true".
  • Disabled rows set aria-disabled="true" and native disabled.

Styling

The component uses Tailwind classes with the astw: prefix:

  • Full width card (astw:w-full)
  • Compact spacing for dense action lists
  • Fixed icon slot for stable alignment
  • Inline spinner for loading state

Use className on ActionPanel to add or override card-level styles.

Examples in This Repo

  • examples/app-module includes an Action Panel Demo resource.
  • The 2 Columns layout page also includes an ActionPanel with loading behavior.
  • Layout - Compose page-level column layouts
  • DescriptionCard - Display structured record fields
  • Badge - Show statuses and semantic labels