Controller & events
Use the controller to drive a table from application UI. Use events to observe accepted changes.
Add a table control
Section titled “Add a table control”A successful-table region receives the controller. For example, add a refresh button above the toolbar:
React
import type { TableRegionProps } from '@inertiax/react-table';import { AppTable } from '@/components/app-table';
function RefreshUsers({ controller, status }: TableRegionProps) { return ( <button type="button" disabled={status.type === 'pending' || status.type === 'scheduled'} onClick={() => controller.refresh()} > Refresh users </button> );}
<AppTable prop="users" customization={{ regions: { beforeToolbar: RefreshUsers } }} />;This region only mounts when a successful result exists. During an invalid-link problem, the table displays its reset control instead.
Get the controller by ref
Section titled “Get the controller by ref”For controls outside the table, pass a React ref through controllerRef:
React
import type { TableController } from '@inertiax/table-core';import { AppTable } from '@/components/app-table';import { useRef } from 'react';
function UsersTable() { const controllerRef = useRef<TableController>(null); return <AppTable prop="users" controllerRef={controllerRef} />;}The ref is set while the renderer owns the session, including during a problem, and cleared on
unmount. A non-null ref alone does not mean state-dependent operations are available; see the
operation contracts below. Declare @inertiax/table-core as a direct dependency when importing its types.
Controller operations
Section titled “Controller operations”| Operation | Argument or result |
|---|---|
getState() |
Immutable TableState snapshot |
setPage(page) |
Positive page number supported by the current result |
setPageSize(pageSize) |
One enabled page-size option; resets page to 1 |
setSorting(sorting) |
Ordered array of { key, direction: 'asc' |; resets page to 1 |
setFilters(filters) |
{ operator: 'and' |; each condition is { key, clause, value } or a nested group, with value: null for a clause that takes none; resets page to 1 |
setSearch(search) |
String, trimmed by the session; resets page to 1 |
getSelection() |
Immutable array of current-result string or JavaScript-safe integer row IDs |
setSelection(selection) |
Current-result string or JavaScript-safe integer row IDs; use clearSelection() for an empty selection |
getColumnVisibility() |
Immutable { [columnKey]: boolean } map |
setColumnVisibility(visibility) |
Partial visibility map merged into current state; keys must be declared, toggleable columns |
resetColumnVisibility() |
Restore visibility from the current Column definitions |
refresh() |
Immediately request the current server state |
retry() |
Replay the current failed request, including a failed reset |
resetProblem() |
Explicitly reset invalid external settings when the problem and integration support it |
During a table problem, no successful state exists. State getters, setters, and refresh() reject
with INERTIAX_TABLE_SESSION_STATE_UNAVAILABLE. Read useTableSnapshot() and check
outcome === 'problem'; use canReset to decide whether to show resetProblem(). A problem
response emits requestProblem with request, componentId, and problem, rather than requestSuccess.
For example:
React
controller.setSorting([ { key: 'role', direction: 'asc' }, { key: 'name', direction: 'desc' },]);
controller.setFilters({ operator: 'and', conditions: [{ key: 'status', clause: 'equals', value: 'active' }],});
controller.setSelection(['user_42']);controller.setColumnVisibility({ email: false });These operations validate state and use the configured integration. Do not mutate the returned state object or construct Inertia URLs yourself. Search and filter requests use the configured debounce; page, page-size, sorting, refresh, and retry requests are immediate. Selection and column visibility are client-only and do not dispatch a request.
Inside a custom renderer region, use useTableController() instead of threading the ref.
State setters also work from a child component’s layout effect or a controller callback ref, including when Activity or Suspense restores the table. Validation and state reads are synchronous; any required request waits until the table connects to its integration.
Retry only a failed request
Section titled “Retry only a failed request”retry() is available only while request status is error. It creates a fresh request identity and
replays its state or reset fields. Calling it while
idle, scheduled, pending, successful, or externally invalid fails with
INERTIAX_TABLE_SESSION_RETRY_UNAVAILABLE; a disposed session instead rejects every controller
operation as disposed. Use refresh() when you want the current state rather than the failed
request’s state.
Observe events
Section titled “Observe events”Event handlers can be application-scoped or component-scoped:
React
<AppTable prop="users" customization={{ events: { selectionChange(event) { console.log(event.selection); }, requestError(event) { reportError(event.error); }, copySuccess(event) { analytics.track('table_cell_copied', { column: event.columnKey, row: event.rowId, }); }, }, }}/>The nine supported event keys and their distinguishing payloads are:
| Event | Emitted when and payload |
|---|---|
stateChange |
Any accepted transition, browser-location update, or result reconciliation changes state; includes componentId, source, previousState (null when recovering from a problem), and state |
requestStart |
An integration request begins; includes request with its identity, reason, state (or reset fields), request key, and cancellation signal |
requestProblem |
request, componentId, problem; valid problem response without a successful result |
requestSuccess |
The accepted latest request succeeds; includes request and result |
requestError |
The accepted latest request fails; includes request and error |
selectionChange |
A controller or built-in UI selection transition is accepted; includes componentId, selection, and state |
columnVisibilityChange |
A controller or built-in UI visibility transition is accepted; includes componentId, columnVisibility, and state |
copySuccess |
A cell value is copied; includes componentId, columnKey, and rowId |
copyError |
Copying fails; includes the copy fields plus error |
A result can prune selection or reset visibility while reconciling new definitions. Observe that
through stateChange with source: 'result'; it is not a second controller transition and does not
also emit selectionChange or columnVisibilityChange. Cancelled or stale requests likewise do not
emit success or error events.
Provider and component handlers both observe their scope. When both exist, the provider handler runs first and the component handler runs second. Events are immutable snapshots. Treat them as notifications; dispatch new state through the controller rather than modifying an event. A handler exception is rethrown asynchronously and does not become a Table request failure.
Read reactive state
Section titled “Read reactive state”Successful-table regions can subscribe through hooks:
React
import { useTableController, useTableState } from '@inertiax/react-table';
function SelectionSummary() { const state = useTableState(); const controller = useTableController();
return ( <button type="button" disabled={state.selection.length === 0} onClick={() => controller.clearSelection()} > Clear {state.selection.length} selected rows </button> );}
<AppTable prop="users" customization={{ regions: { beforeToolbar: SelectionSummary } }} />;useTableSnapshot() returns state, the current result envelope, and status from one immutable
snapshot. useTableState(), useTableStatus(), and useTableEnvelope() subscribe to the narrower
slice. These hooks must run inside the current Table renderer scope. useTableState() and
useTableEnvelope() require a successful outcome; see Custom table layouts
when replacing the whole renderer.
For operations using selected IDs, see Authorization & security.