Row Actions
Define the buttons of every row in the Table class. The component renders them in a trailing
column, so a page needs no #actions slot.
$table
->rowAction('Edit', url: fn (Room $room) => route('rooms.edit', $room))
->rowAction(
'Delete',
url: fn (Room $room) => route('rooms.destroy', $room),
method: 'delete',
confirm: 'Delete this room?',
variant: 'destructive',
visible: fn (Room $room) => $viewer->can('delete', $room),
disabled: fn (Room $room) => $room->units_count > 0 ? 'The room still has units' : false,
);
Signature
rowAction(
string $label,
string|Closure|null $url = null,
?string $route = null,
string $method = 'get',
?string $confirm = null,
string $variant = 'outline',
bool|Closure $visible = true,
bool|string|Closure $disabled = false,
?string $key = null,
bool|string $download = false,
): self
| Parameter | Description |
|---|---|
label |
Button text |
url |
A fixed url, or a callback receiving the row item. Returning null hides the action for that row |
route |
A route name resolved as route($route, $item); use url when the route needs more parameters |
method |
get, post, put, patch or delete |
confirm |
Question asked before the action runs |
variant |
Button variant: default, destructive, outline, secondary, ghost or link |
visible |
false or a callback returning false leaves the action out of the payload for that row |
disabled |
true, or a callback returning true or a reason string. The reason is shown as the button's tooltip |
key |
Identifier of the action, defaults to the slug of the label. Registering a key again replaces the action |
download |
true or a file name: the action downloads a file instead of visiting a page. Only with the get method |
url or route is required.
Authorization
Hidden actions are never sent to the browser, so visible is the place for policy checks. Keep the
same check on the route the action points to: hiding a button does not protect the endpoint.
Use disabled with a reason when the user should see that the action exists but cannot use it now.
How They Run
getactions render as a link. A click visits the url through Inertia; ctrl, cmd and middle clicks open a new tab as usual.- Other methods are sent as an Inertia visit with that method and
preserveScroll. With thehttptransport they are sent withfetch()and the table reloads afterwards. confirmuseswindow.confirm()unless the component gets aconfirmprop:
<TableBuilder :table="table" :confirm="(message) => dialog.ask(message)"/>
The prop may return a boolean or a promise of one. Bulk actions use the same prop and pass a second details argument; see
Bulk Actions.
Downloads
A file download, such as an invoice PDF, must not go through an Inertia visit: Inertia expects a page
back and shows the file as an error. Mark the action with download:
$table->rowAction(
'PDF',
url: fn (Invoice $invoice) => route('invoices.pdf', $invoice),
download: true,
);
$table->rowAction('CSV', url: fn (Report $report) => route('reports.csv', $report), download: 'report.csv');
The component renders a plain link with a download attribute, so the browser fetches the file
itself and the page stays where it is. A string sets the suggested file name; with true the
Content-Disposition header of the response decides, which is what response()->download() and
Storage::download() send. A download with a confirm question asks first and then starts the
download. The run function of the #actions slot downloads too.
The resolved action carries download: true or the file name; other actions have no download key.
Custom Rendering
An #actions slot still wins over the built-in buttons. It receives the resolved actions of the
row and a run function, so you can restyle them and keep the behaviour:
<TableBuilder :table="table">
<template #actions="{actions, run}">
<DropdownMenu>
<DropdownMenuItem
v-for="action in actions"
:key="action.key"
:disabled="action.disabled"
@click="run(action)"
>
{{ action.label }}
</DropdownMenuItem>
</DropdownMenu>
</template>
</TableBuilder>
The resolved actions are also in table.rowActions, an array with one list of actions per row.
