4.8 KiB
Filament Actions UX Standard
Canonical rules for row actions, bulk actions, header actions, and inspect affordances on all Filament table surfaces. This standard consolidates the Action Surface Contract from the constitution and
docs/ui/action-surface-contract.md.
Last reviewed: 2026-03-30
Governing Principle
Filament-native first.
Action patterns use native Filament action APIs.
The constitution's Action Surface Contract (in .specify/memory/constitution.md) is the authoritative source for safety and RBAC rules.
This document provides the quick-reference standard for implementation.
Required Surfaces
Every list/table must define:
- Header Actions — primary CTA (create, sync, etc.)
- Row Actions — inspect + contextual operations
- Bulk Actions — where batch operations exist
- Empty-State CTA — exactly 1 primary action, RBAC-gated
Inspect Affordance (Required)
Every list-style surface must provide a way to open a record.
Default: clickable rows for list-first and registry surfaces
$table->recordUrl(fn ($record) => /* route to view/edit */)
Use this default for:
- CRUD / List-first resources
- Read-only registries / reports
- Reporting and evidence registers such as Review Register and Evidence Overview
Explicit inspect for queue and audit surfaces
Use an Inspect row action or equivalent same-page selected detail when chronology or queue context must remain visible.
- Audit / history pages use explicit inspect
- Queue / review pages use explicit inspect
- These surfaces should not also expose row click as a competing open path
Alternative: primary link column
Use only when clickable rows are impractical on a clickable-row surface.
PrimaryLinkColumnrequires a non-empty declaration reason- It is not a fallback for queue / review or audit surfaces
Rule: no lone "View" button
If an open action is the only row action on a clickable-row surface, prefer row click and set actions([]) to avoid an unnecessary Actions column.
Row Action Limits
- Max 2 visible row actions (typically View/Edit or Edit/Delete)
- Everything else goes into an
ActionGrouplabeled "More" - Destructive actions must never be the primary visible action
- On clickable-row surfaces, prefer zero inline row actions unless a single justified shortcut materially improves the workflow
Bulk Actions
- Bulk actions must be grouped via
BulkActionGroup - Destructive bulk actions require confirmation
- Typed confirmation may be required for large/bulk changes
- Do not leave an empty
BulkActionGroupplaceholder visible once filters, record state, or RBAC remove every effective action
Destructive Action Safety
- All destructive actions must use
->requiresConfirmation() - Destructive actions must not be styled as primary
- Confirmation text must clearly describe the consequence
- Server-side authorization must still enforce the action regardless of UI confirmation
This is a constitution-level non-negotiable (RBAC-UX-005).
Action Consistency
Standard action labels
| Action | Label | Icon guidance |
|---|---|---|
| Inspect record | "Inspect" | heroicon-o-eye |
| Edit record | "Edit" | heroicon-o-pencil-square |
| Delete record | "Delete" | heroicon-o-trash |
| Archive record | "Archive" | heroicon-o-archive-box |
| Restore record | "Restore" | heroicon-o-arrow-uturn-left |
| Force delete | "Force Delete" | heroicon-o-trash |
Notes:
- Clickable-row surfaces normally do not render a
VieworInspectrow action at all. - Reporting/evidence registers keep row click primary and should not add a duplicate
View review-style action.
Action ordering in "More" group
- Navigation or inspect helpers first
- Non-destructive workflow or lifecycle actions next
- Destructive actions last
- Do not render an empty
ActionGroupplaceholder
Representative expectations:
Policies:Export, thenSync, then destructive ignore/delete actionsBackup schedules:Run now/Retrybefore archive or force deleteWorkspaces: row click stays primary and the secondaryEditshortcut lives underMore
RBAC Enforcement
- Non-member access: abort(404), do not leak existence
- Member without capability: visible but disabled with tooltip
- Server-side must enforce via
Gate::authorize(...)or Policy method - Missing server-side authorization is a P0 security bug
Spec / DoD Gate
Every spec with UI changes must include a UI Action Matrix listing:
- Which actions exist on which surfaces
- Which are destructive and how confirmation is handled
- Which capabilities gate each action
A change is not "Done" unless the Action Surface Contract is met.
Canonical Sources
- Constitution:
.specify/memory/constitution.md→ "Filament UI — Action Surface Contract" - Detailed reference:
docs/ui/action-surface-contract.md