Template Refs
Template refs give you access to the same useTable and useActions methods you'd get from a custom table, without actually building one. Attach a ref to the default <Table> component, then call its exposed methods from anywhere in your page (add or remove filters, toggle row selection, change sort, trigger actions) to drive the table from custom buttons, keyboard shortcuts, or other components.
Basic Usage
To access the table's methods, create a template ref and call the exposed methods:
<script setup>
import { ref } from 'vue'
import { Table } from '@inertiaui/table-vue'
const props = defineProps({
users: Object,
})
const tableRef = ref()
function addFilter() {
const filter = props.users.filters.find(f => f.attribute === 'status')
tableRef.value.addFilter(filter)
}
function selectAll() {
tableRef.value.toggleItem('*')
}
</script>
<template>
<Table ref="tableRef" :resource="users" />
</template>import { useRef } from 'react'
import { Table } from '@inertiaui/table-react'
export default function Users({ users }) {
const tableRef = useRef()
function addFilter() {
const filter = users.filters.find(f => f.attribute === 'status')
tableRef.current.addFilter(filter)
}
function selectAll() {
tableRef.current.toggleItem('*')
}
return <Table ref={tableRef} resource={users} />
}Table Methods
| Method | Description |
|---|---|
addFilter(filter) | Add a filter |
removeFilter(filter) | Remove a filter |
resetAllFilters() | Remove all active filters |
setFilter(attribute, clause, value) | Set a filter by attribute, clause, and value |
setSearch(search) | Set the search query |
toggleColumn(column) | Show/hide a column |
setSort(sort) | Set the table sort |
sortByColumn(column) | Cycle a column through ascending, descending, and default sort |
loadFilterOptions(attribute) | Load options for a lazy filter |
setPerPage(perPage) | Change items per page |
makeSticky(column) | Make columns sticky |
undoSticky(column) | Remove sticky positioning |
putState(newState) | Replace the table state |
reloadTable() | Reload the table and its configured partial reload props |
toggleItem(key) | Toggle item selection (use '*' for all) |
performAction(action, keys) | Execute an action after displaying any required confirmation |
performAsyncExport(export) | Start a queued export |
visitPaginationUrl(url) | Navigate using a server-provided pagination URL |
visitTableUrl(url, options) | Visit a table URL with Inertia options |
Table State
| Property | Type | Description |
|---|---|---|
state | Object | Reactive table state |
hasFilters | Boolean | Whether filters are active |
hasSelectableRows | Boolean | Whether rows are selectable |
selectedItems | Array | Selected item keys |
allItemsAreSelected | Boolean | Whether all items in the configured selection scope are selected |
someItemsAreSelected | Boolean | Whether the selection is partial |
isPerformingAction | Boolean | Whether an action or export is running |
loadedFilterOptions | Object | Loaded options keyed by filter attribute |
isNavigating | Boolean | Whether navigating |
Accessing State
You may access the table's reactive state. In Vue, the state is automatically reactive. In React, access the state in response to user interactions or component lifecycle events:
<script setup>
import { ref } from 'vue'
import { Table } from '@inertiaui/table-vue'
const props = defineProps({
users: Object,
})
const tableRef = ref()
function checkState() {
// Access state when needed
const selectedItems = tableRef.value.selectedItems
const currentSearch = tableRef.value.state.search
console.log(`Selected ${selectedItems.length} items`)
console.log(`Current search: ${currentSearch}`)
}
</script>
<template>
<div>
<button @click="checkState">
Check State
</button>
<Table ref="tableRef" :resource="users" />
</div>
</template>function MyComponent({ users }) {
const tableRef = useRef()
function checkState() {
// Access state when needed
const selectedItems = tableRef.current.selectedItems
const currentSearch = tableRef.current.state.search
console.log(`Selected ${selectedItems.length} items`)
console.log(`Current search: ${currentSearch}`)
}
return (
<div>
<button onClick={checkState}>
Check State
</button>
<Table ref={tableRef} resource={users} />
</div>
)
}Observing Changes
The Table emits change in Vue and calls onChange in React with { table, actions }. Use these to display the current search, selection, or other state outside the component.
In Vue, bind @change="handleChange" to the Table and render status where you need it. Import ref from Vue and the UseTableReturn and UseActionsReturn types from @inertiaui/table-vue:
const status = ref('No selection')
function handleChange({ table, actions }: { table: UseTableReturn; actions: UseActionsReturn }) {
status.value = `${actions.selectedItems.value.length} selected; search: ${table.state.value.search || 'none'}`
}Vue unwraps the values exposed through the template ref, so you may use tableRef.value.state.search in JavaScript. The change event and Slots receive refs instead. Use .value to access them, for example table.state.value.search and actions.selectedItems.value.
In React, changing a ref does not trigger a render. Use onChange to copy the values your controls need into React state. The callback receives new table and actions objects on each render. Compare the values before updating state to avoid a render loop.
Observing multiple values in React
The following example stores the table and action state for use in external controls. Import useState and useCallback from React, and TableResource, UseTableReturn, and UseActionsReturn from @inertiaui/table-react:
interface TableScope {
resource: TableResource
table: UseTableReturn
actions: UseActionsReturn
}Inside your component, compare the values used by the controls before updating state:
const [scope, setScope] = useState<TableScope | null>(null)
const handleChange = useCallback(
({ table, actions }: { table: UseTableReturn; actions: UseActionsReturn }) => {
setScope((current) => {
if (
current?.resource === users &&
current.table.state === table.state &&
current.table.loadedFilterOptions === table.loadedFilterOptions &&
current.table.isNavigating === table.isNavigating &&
current.actions.selectedItems === actions.selectedItems &&
current.actions.isPerformingAction === actions.isPerformingAction
) {
return current
}
return { resource: users, table, actions }
})
},
[users],
)Pass handleChange to the Table's onChange prop. Once scope is available, use scope.table and scope.actions to render your controls. To reload the table, call tableRef.current.reloadTable().
Each useTable instance has its own state. To control an existing Table, use its ref instead of calling useTable(users) again. Updating the resource prop does not reset the Table's state; use methods such as setFilter, setSearch, or putState to update it.
Custom Filter Controls
You may build custom filter interfaces that integrate with the table's filtering system. setFilter enables a filter and sets its clause and value in one call, without needing to call addFilter first:
<script setup>
import { ref } from 'vue'
import { Table } from '@inertiaui/table-vue'
const props = defineProps({
users: Object,
})
const tableRef = ref()
function applyStatusFilter(status) {
tableRef.value.setFilter('status', 'equals', status)
}
function clearFilters() {
tableRef.value.resetAllFilters()
}
</script>
<template>
<div class="mb-4 space-x-2">
<button @click="applyStatusFilter('active')">Show Active</button>
<button @click="applyStatusFilter('inactive')">Show Inactive</button>
<button @click="clearFilters">Clear Filters</button>
</div>
<Table ref="tableRef" :resource="users" />
</template>function MyComponent({ users }) {
const tableRef = useRef()
function applyStatusFilter(status) {
tableRef.current.setFilter('status', 'equals', status)
}
function clearFilters() {
tableRef.current.resetAllFilters()
}
return (
<div>
<div className="mb-4 space-x-2">
<button onClick={() => applyStatusFilter('active')}>
Show Active
</button>
<button onClick={() => applyStatusFilter('inactive')}>
Show Inactive
</button>
<button onClick={clearFilters}>
Clear Filters
</button>
</div>
<Table ref={tableRef} resource={users} />
</div>
)
}Programmatic Search
Use setSearch to update the search query programmatically:
<script setup>
import { ref } from 'vue'
import { Table } from '@inertiaui/table-vue'
const props = defineProps({
users: Object,
})
const tableRef = ref()
function searchForUser(name) {
tableRef.value.setSearch(name)
}
</script>
<template>
<div class="mb-4 space-x-2">
<button @click="searchForUser('John')">Search for John</button>
<button @click="searchForUser('')">Clear Search</button>
</div>
<Table ref="tableRef" :resource="users" />
</template>function MyComponent({ users }) {
const tableRef = useRef()
function searchForUser(name) {
tableRef.current.setSearch(name)
}
return (
<div>
<div className="mb-4 space-x-2">
<button onClick={() => searchForUser('John')}>
Search for John
</button>
<button onClick={() => searchForUser('')}>
Clear Search
</button>
</div>
<Table ref={tableRef} resource={users} />
</div>
)
}Custom Bulk Actions
You may trigger bulk actions programmatically and control row selection:
<script setup>
import { ref } from 'vue'
import { Table } from '@inertiaui/table-vue'
const props = defineProps({
users: Object,
})
const tableRef = ref()
function selectAll() {
tableRef.value.toggleItem('*')
}
function bulkDelete() {
const deleteAction = props.users.actions.find(a => a.id === 'delete')
if (deleteAction && tableRef.value.selectedItems.length > 0) {
tableRef.value.performAction(deleteAction, tableRef.value.selectedItems)
}
}
</script>
<template>
<div class="mb-4 space-x-2">
<button @click="selectAll">Toggle All</button>
<button @click="bulkDelete" :disabled="!tableRef?.selectedItems?.length">
Delete Selected ({{ tableRef?.selectedItems?.length || 0 }})
</button>
</div>
<Table ref="tableRef" :resource="users" />
</template>function MyComponent({ users }) {
const tableRef = useRef()
function selectAll() {
tableRef.current.toggleItem('*')
}
function bulkDelete() {
const deleteAction = users.actions.find(a => a.id === 'delete')
if (deleteAction && tableRef.current.selectedItems.length > 0) {
tableRef.current.performAction(deleteAction, tableRef.current.selectedItems)
}
}
return (
<div>
<div className="mb-4 space-x-2">
<button onClick={selectAll}>Toggle All</button>
<button onClick={bulkDelete}>
Delete Selected
</button>
</div>
<Table ref={tableRef} resource={users} />
</div>
)
}