Custom Table Component
Inertia Table may be used in a fully headless mode. Build your own Vue or React component and use useTable for search, filters, sorting, columns, and pagination. Use useActions for selection, actions, and exports. The Laravel table definition remains the same.
To control the default Table component without building your own, see Template Refs.
Advanced usage
The composables on this page are stable and fully supported, but the custom components you build with them are your own. We're happy to help with questions about the useTable and useActions API itself, but we cannot debug or maintain custom table implementations.
Creating a Custom Table
Import useTable and useActions from @inertiaui/table-vue or @inertiaui/table-react. Both accept the table resource passed from Laravel as the users prop.
In Vue, pass a getter so the composables can read the latest resource after navigation. Their state and computed values are refs. Import reactive from Vue to unwrap them, as below. React hooks return plain values; call them inside your component.
const table = reactive(useTable(() => props.users))
const actions = reactive(useActions(() => props.users))const table = useTable(users)
const actions = useActions(users)Render rows from users.results.data, using each item's _primary_key as its key. Use the resource's column definitions for headers and cells, and table.state.columns to determine which columns are visible. In Vue, import computed to keep the visible columns reactive:
const columns = computed(() => props.users.columns.filter((column) => table.state.columns[column.attribute]))const columns = users.columns.filter((column) => table.state.columns[column.attribute])For sortable headers, call table.sortByColumn(column) and read the current direction with table.isSortedByColumn(column). For pinned columns, use table.leftStickyColumns and table.rightStickyColumns to calculate sticky positions in your layout.
Search and Filters
Bind a search input to table.state.search and call setSearch when it changes. The composable handles navigation and the configured debounce time:
<input
data-testid="example-search"
type="search"
:value="table.state.search ?? ''"
@input="table.setSearch(($event.target as HTMLInputElement).value)"
/><input
data-testid="example-search"
type="search"
value={table.state.search ?? ''}
onChange={(event) => table.setSearch(event.target.value)}
/>Call setFilter(attribute, clause, value) to enable and update a filter. Match the value to its clause: ranges take two values, in and not_in take arrays, and clauses such as is_true and is_not_set need no value. A single-choice set filter still uses an array for an in clause. See Filtering for the available filter types and clauses.
To load the options for a lazy filter, call loadFilterOptions with its attribute. The following example receives table as a prop. Import the TableFilter type from @inertiaui/table-vue or @inertiaui/table-react:
function addFilter(filter: TableFilter) {
props.table.addFilter(filter)
if (filter.lazy) {
props.table.loadFilterOptions(filter.attribute)
}
}function addFilter(filter: TableFilter) {
table.addFilter(filter)
if (filter.lazy) {
table.loadFilterOptions(filter.attribute)
}
}Read the options from table.loadedFilterOptions[filter.attribute], falling back to filter.options for filters whose options are included in the resource.
Selection and Actions
To select a row, call toggleItem with its primary key. Use actions.selectedItems to determine whether its checkbox is checked. Disable the checkbox when _is_selectable is false or an action is running:
<input
type="checkbox"
:aria-label="`Select ${user.name}`"
:disabled="user._is_selectable === false || actions.isPerformingAction"
:checked="actions.selectedItems.includes(user._primary_key!)"
@change="actions.toggleItem(user._primary_key!)"
/><input
type="checkbox"
aria-label={`Select ${user.name}`}
disabled={user._is_selectable === false || actions.isPerformingAction}
checked={actions.selectedItems.includes(user._primary_key!)}
onChange={() => actions.toggleItem(user._primary_key!)}
/>toggleItem('*') follows the table's configured bulk-selection mode. Use allItemsAreSelected and someItemsAreSelected for the select-all checkbox.
To run an action, call performAction(action, keys). Your component must check whether the action is authorized and enabled, show a confirmation dialog when confirmationRequired is true, and handle any errors. Use isPerformingAction to indicate that the action is running.
For Row Actions, getActionForItem(action, item._actions[index]) returns the visibility and bindings for that item. For links, navigate to the item's action URL.
Custom actions return an onFinish callback from performAction. Call it after your custom work to clear the busy state and selection. See Row Actions and Bulk Actions for action configuration.
Pagination and Reloading
Use setPerPage to change the page size. Pass the server's next_page_url and prev_page_url to visitPaginationUrl; this works with full, simple, and cursor pagination. Here, resource is the table resource and busy combines table.isNavigating and actions.isPerformingAction:
<button type="button" :disabled="busy || !resource.results.next_page_url" @click="table.visitPaginationUrl(resource.results.next_page_url!)">
Next page
</button><button
type="button"
disabled={busy || !resource.results.next_page_url}
onClick={() => table.visitPaginationUrl(resource.results.next_page_url!)}
>
Next page
</button>reloadTable refreshes the table and its configured reload props without clearing the current state.
User Card Grids
The same APIs work with lists and card grids. Render users.results.data as cards, use _primary_key as the key, and check table.state.columns[attribute] to decide which fields to display. Search, filters, selection, actions, and pagination remain the same.
You may display 25 cards per page by calling perPageOptions([25, 50, 100]) on the Laravel table. The number of cards in each row is controlled by your CSS; it does not affect pagination.
Exports and Saved Views
Download exports use their signed URL, with selected keys added when limitToSelectedRows is enabled. Queued exports use performAsyncExport; display the returned response.dialogTitle and response.dialogMessage when provided. Only enable an export when its authorized property is true. See Exporting for configuration.
Save and delete views through the URLs provided in resource.views, and apply a view with putState(view.state). Keep the existing list of views when handling partial reloads, as these responses contain an empty views list.
useTable uses resource.state as its initial state. Updating the resource prop does not reset this state. To change it, use methods such as setFilter and setSearch, or pass a state object to putState.
The Resource Object
The resource prop is the data that is passed to your component, originating from the Laravel backend. The resource object contains the following data:
| Key | Description |
|---|---|
actions | The actions of the table |
columns | The columns of the table |
debounceTime | The debounce time for the search input and filters |
defaultPerPage | The default per page value |
defaultSort | The default sort value |
exports | The exports of the table |
filters | The filters of the table |
name | The name of the table |
pagination | Whether the table should paginate |
perPageOptions | The options for the per page select |
results | The results of the query (the actual data) |
search | The attributes that are searchable |
state | The state of the table |
Columns
The columns key is an array of objects that define the columns of the table. Each column object has the following properties:
| Key | Description |
|---|---|
alignment | The alignment of the column (left, center, right) |
attribute | The attribute of the Eloquent model |
header | The title of the column |
meta | The custom Metadata of the column |
sortable | Whether the column is sortable |
toggleable | Whether the column can be toggled |
visibleByDefault | Whether the column is visible by default |
Filters
The filters key is an array of objects that define the filters of the table. Each filter object has the following properties:
| Key | Description |
|---|---|
attribute | The attribute of the Eloquent model that should be filtered |
clauses | The available clauses of the filter |
label | The label of the filter |
meta | The custom Metadata of the filter |
type | The type of the filter (text, numeric, set, date, boolean) |
Actions
The actions key is an array of objects that define the actions of the table. Each action object has the following properties:
| Key | Description |
|---|---|
asBulkAction | Whether the action should be displayed as a bulk action |
asRowAction | Whether the action should be displayed as a row action |
authorized | Whether the user is authorized to perform the action |
confirmationCancelButton | The label of the confirmation dialog cancel button |
confirmationConfirmButton | The label of the confirmation dialog confirm button |
confirmationMessage | The message of the confirmation dialog |
confirmationRequired | Whether the action requires confirmation |
confirmationTitle | The title of the confirmation dialog |
dataAttributes | The custom Data Attributes of the action |
icon | The custom icon of the action |
isLink | Whether the action is a link |
label | The label of the action |
meta | The custom Metadata of the action |
showLabel | Whether the label should be displayed |
variant | The button or link variant |
url | The URL of the action |
Exports
The exports key is an array of objects that define the exports of the table. Each export object has the following properties:
| Key | Description |
|---|---|
label | The label of the export |
authorized | Whether the user is authorized to perform the export |
url | The URL of the export |
dataAttributes | The custom Data Attributes of the export |
meta | The custom Metadata of the export |
State
The state key is an object that contains the state of the table. The state object has the following properties:
| Key | Description |
|---|---|
columns | An object that contains the visibility of the columns |
filters | An object that contains the filter state (enabled, value, clause) |
perPage | The per page value |
search | The search value |
sort | The sort value |
sticky | The pinned column attributes |
page / cursor | The pagination state |
Metadata
You may attach metadata to Actions and Links, Columns, Exports, and Filters. The default Table component ignores this metadata, but it's useful when building a custom Table component.