Selection & Actions
Row selection with checkboxes, and bulk actions that operate on the selected set.
Row selection adds a checkbox column (with select-all in the header) and tracks selected row ids. Enable it explicitly, or implicitly by passing actions — the checkbox column appears whenever actions is non-empty or features.rowSelection is true.
<BetterTable
id="tickets"
columns={columns}
data={data}
features={{ rowSelection: true }}
initialSelectedRows={new Set(['42'])}
onSelectionChange={(selected) => console.log([...selected])}
/>Row identity comes from rowConfig.getId(row) when provided, falling back to the row's id field — set getId whenever your rows have a different key.
Plain row selection needs no module — it is part of core.
Bulk actions
The actions toolbar is an opt-in module. Add it once:
bunx @better-tables/cli add actionsThen wire it into the table's actionsToolbar slot. actions is a TableAction[]; the toolbar renders above the table and invokes handlers with the current selection:
import { Archive, Trash2 } from 'lucide-react';
import { ActionsToolbar } from '@/components/better-tables-ui/table/actions-toolbar';
<BetterTable
id="tickets"
columns={columns}
data={data}
slots={{ actionsToolbar: ActionsToolbar }}
actions={[
{
id: 'archive',
label: 'Archive',
icon: Archive,
handler: async (selectedIds, selectedData) => {
await archiveTickets(selectedIds);
},
},
{
id: 'delete',
label: 'Delete',
icon: Trash2,
variant: 'destructive',
confirmationDialog: {
title: 'Delete tickets?',
description: 'This cannot be undone.',
confirmLabel: 'Delete',
},
handler: async (selectedIds) => deleteTickets(selectedIds),
},
]}
/>TableAction (complete)
| Field | Purpose |
|---|---|
id | Unique action identifier |
label | Button label |
icon | Icon component (optional) |
variant | Button visual variant: 'default' | 'destructive' | 'secondary' |
handler(selectedIds, selectedData?) | The work — sync or async |
confirmationDialog | { title, description, confirmLabel?, cancelLabel?, destructive? } — confirm before running |
isVisible(selectedIds, selectedData?) | Hide the action for some selections |
isEnabled(selectedIds, selectedData?) | Disable (but show) the action |
meta | Arbitrary metadata passthrough |
After a handler resolves, refetch your data — the table doesn't mutate rows itself. Selection state can also be seeded with initialSelectedRows and observed via onSelectionChange (see the props reference).
To customize the toolbar (for example, the selected-count label), edit the copied actions-toolbar.tsx directly; add app-specific toast handling there as needed.