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
import { ActionPanel } from "@tailor-platform/app-shell";Basic Usage
<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
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | Required | Card title (for example, "Actions") |
actions | ActionItem[] | Required | List of actions to render |
className | string | - | Additional CSS classes for the card root |
ActionItem
| Property | Type | Default | Description |
|---|---|---|---|
key | string | Required | Unique key for stable rendering |
label | string | Required | Action label shown to users |
icon | ReactNode | Required | Icon rendered in a fixed 16px slot |
onClick | () => void | Promise<void> | - | Click handler for the action |
disabled | boolean | false | Disables interaction and applies disabled styling |
loading | boolean | false | Shows spinner, disables interaction, sets busy UI |
Behavior
- Rows are rendered as
<button type="button">elements. disabledorloadingmakes the row non-interactive.- When
loadingistrue, 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:
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.
// 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:
ActionPanelmust be rendered insideAppShell(which provides the requiredCommandPaletteProvider). 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:
- Backend returns document data and available action keys.
- Frontend maps each key to a registry entry (
label,icon,execute). - Page builds
ActionItem[]and wiresonClick. - Page controls
loadingper key and passes it toActionPanel.
This keeps ActionPanel simple and reusable across entity types.
Accessibility
- Action list uses
role="list"and each row wrapper usesrole="listitem". - Buttons are keyboard accessible and include focus-visible states.
- Loading rows set
aria-busy="true". - Disabled rows set
aria-disabled="true"and nativedisabled.
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-moduleincludes an Action Panel Demo resource.- The 2 Columns layout page also includes an ActionPanel with loading behavior.
Related Components
- Layout - Compose page-level column layouts
- DescriptionCard - Display structured record fields
- Badge - Show statuses and semantic labels
Related Concepts
- Modules and Resources - Organize pages and routes
- Routing and Navigation - Navigation patterns