Skip to content

[6.x] Actions#18749

Merged
brianjhanson merged 29 commits intofeature/inertia-uifrom
feature/actions
Apr 28, 2026
Merged

[6.x] Actions#18749
brianjhanson merged 29 commits intofeature/inertia-uifrom
feature/actions

Conversation

@brianjhanson
Copy link
Copy Markdown
Contributor

@brianjhanson brianjhanson commented Apr 23, 2026

There's a problem I've been wrestling. How do you determine server side what code should be run on the client? There are a few libraries that take a run at this. HTMX, Datastar, Stimulus, and probably roughly 1,000 more. Each of these could have gotten the job done, but in the end we're rolling our own, at least for the moment. The main reason being that we already kind of were.

In Craft 5 (and before) you're able to pass an array of items into the disclosureMenu method of the craft\helpers\Cp class. If you know the specific encantation to make them work. A sample item might look something like this

{
   "label": "Edit Entry",
   "icon": "pen-to-square",
   "action": "entries/save-entry",
   "params": {"entryId": 42},
   "description": "Save changes to this entry",
   "confirm": "Are you sure you want to save?",
   "redirect": "entries",
   "destructive": false,
   "disabled": false,
   "hidden": false,
   "selected": false,
   "requireElevatedSession": true
 }

I chose to build on this solution rather than implement something entirely new mostly for the ease of migration. Moving a few properties around felt easier than refactoring to a new library.

With this PR, actions have a handful of canonical types you can use to dictate functionality.

Type What it does
clipboard Writes a string to the clipboard
http Fires a fetch request (GET/POST/PATCH/DELETE)
event Dispatches a CustomEvent on window
download Triggers a file download

Action Typescript definition

type BaseAction =
  | { type: 'clipboard'; value: string }
  | { type: 'http'; method?: 'GET' | 'POST' | 'PATCH' | 'DELETE'; url: string; body?: Record<string, unknown>; confirm?: string }
  | { type: 'event'; name: string; detail?: Record<string, unknown>; confirm?: string }
  | { type: 'download'; url: string; filename?: string }

The confirm field on http and event primitives shows a native browser confirmation dialog before proceeding.

Using <craft-action-item/> you can pass one of these actions into the action param to dictate the functionality.

If you'd like your action to provide feedback, you can provide that as a separate param.

Feedback config

'feedback' => [
    'loading' => ['message' => 'Saving...'],          // shown while action is in-flight
    'success' => ['message' => 'Saved!'],  // shown on success
    'error'   => ['message' => 'Save failed'], // shown on failure
],

A complete example might look something like

<craft-action-item
  icon="clipboard"
  .action=${{ type: 'clipboard', value: entry.handle }}
  .feedback=${{ success: { message: 'Copied!' } }}
>
  Copy handle
</craft-action-item>

Powers moments like this

CleanShot.2026-04-28.at.08.41.01.mp4

Base automatically changed from feature/plugins-page to feature/inertia-ui April 24, 2026 19:04
{
return [
...parent::safeActionMenuItems(),
[
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense here to have some kind of action object builder?

new ActionMenuItem()
    ->icon('clipboard')
    ->label(t('Copy handle'))
    // ...

Copy link
Copy Markdown
Contributor Author

@brianjhanson brianjhanson Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure, I still have dreams of a PHP component system, I just haven't put any of it together yet.

In this particular case, these docs are out of date. I just forgot to remove it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still have dreams of a PHP component system

:)

@brianjhanson brianjhanson marked this pull request as ready for review April 28, 2026 18:39
@brianjhanson brianjhanson merged commit 45a1395 into feature/inertia-ui Apr 28, 2026
16 checks passed
@brianjhanson brianjhanson deleted the feature/actions branch April 28, 2026 18:39
@brianjhanson brianjhanson mentioned this pull request Apr 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants