Row selection with checkboxes and keyboard support.
Row selection allows users to select one or multiple rows using checkboxes. Selected rows can be used for bulk actions, exports, or other operations.
Add a selection column to enable row selection:
import { getSelectionColumn } from '@workspace/active-grid';
const columns = [
getSelectionColumn<User>(),
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
];
<ActiveGrid columns={columns} data={data} {...} />The getSelectionColumn helper creates a complete selection column with header and cell checkboxes:
import { getSelectionColumn } from '@workspace/active-grid';
const selectionColumn = getSelectionColumn<User>({
size: 40,
enablePinning: true,
enableHiding: false,
});getSelectionColumn<TData>({
size?: number; // Column width (default: 40)
enablePinning?: boolean; // Allow pinning (default: true)
enableHiding?: boolean; // Allow hiding (default: false)
enableSorting?: boolean; // Allow sorting (default: false)
})For custom implementation:
import { SelectionCell } from '@workspace/active-grid';
{
id: 'select',
size: 40,
enableSorting: false,
enableHiding: false,
header: ({ table }) => (
<SelectionCell
checked={table.getIsAllRowsSelected()}
indeterminate={table.getIsSomeRowsSelected()}
onCheckedChange={(value) => table.toggleAllRowsSelected(!!value)}
/>
),
cell: ({ row }) => (
<SelectionCell
checked={row.getIsSelected()}
disabled={!row.getCanSelect()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
/>
),
}Click a row's checkbox to select it. Click again to deselect.
// Row is selected
row.getIsSelected() === trueClick multiple checkboxes to select multiple rows. Hold Shift while clicking to select a range.
// Get all selected rows
const selectedRows = table.getSelectedRowModel().rows;Click the header checkbox to select all rows on the current page (client mode) or all matching rows (server mode).
// Select all rows
table.toggleAllRowsSelected(true);
// Deselect all rows
table.toggleAllRowsSelected(false);import { useActiveGrid } from '@workspace/active-grid';
function MyComponent() {
const table = useActiveGrid();
// Select specific rows by ID
const selectRows = (ids: string[]) => {
table.setRowSelection(
ids.reduce((acc, id) => ({ ...acc, [id]: true }), {})
);
};
// Select all rows
const selectAll = () => {
table.toggleAllRowsSelected(true);
};
// Clear selection
const clearSelection = () => {
table.resetRowSelection();
};
// Get selected row data
const selectedData = table.getSelectedRowModel().rows.map(row => row.original);
// Get selection count
const selectedCount = table.getSelectedRowModel().rows.length;
}import { useState } from 'react';
import { RowSelectionState } from '@tanstack/react-table';
function MyComponent() {
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
return (
<ActiveGrid
columns={columns}
data={data}
state={{ rowSelection }}
onRowSelectionChange={setRowSelection}
enableRowSelection
{...}
/>
);
}// RowSelectionState is a map of row IDs to boolean
{
'row-1': true,
'row-2': true,
'row-5': true,
}const table = useActiveGrid();
// Get selection state object
const selectionState = table.getState().rowSelection;
// Check if specific row is selected
const isSelected = table.getState().rowSelection['row-id'] === true;
// Get all selected row models
const selectedRows = table.getSelectedRowModel().rows;
// Get selected row data
const selectedData = selectedRows.map(row => row.original);Disable selection for specific rows:
<ActiveGrid
columns={columns}
data={data}
enableRowSelection={(row) => {
// Only allow selection for active users
return row.original.status === 'active';
}}
{...}
/>Or in column definition:
{
id: 'select',
cell: ({ row }) => (
<SelectionCell
checked={row.getIsSelected()}
disabled={row.original.status === 'locked'}
onCheckedChange={(value) => row.toggleSelected(!!value)}
/>
),
}For server-side mode, maintain selection state across page changes:
For server-side selection across pages, you must provide getRowId to ensure consistent row identification.
Use selected rows for bulk operations:
Integrate selection info in the toolbar:
getRowId for server-side selectionSelected rows automatically receive data-state="selected" attribute:
import { useState } from 'react';
import { RowSelectionState } from '@tanstack/react-table';
function MyComponent() {
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
return (
<ActiveGrid
mode="server"
fetchFn={fetchData}
columns={columns}
state={{ rowSelection }}
onRowSelectionChange={setRowSelection}
getRowId={(row) => row.id} // Important for persistent selection
{...}
/>
);
}function BulkActions() {
const table = useActiveGrid();
const selectedRows = table.getSelectedRowModel().rows;
const selectedCount = selectedRows.length;
const handleBulkDelete = async () => {
const ids = selectedRows.map(row => row.original.id);
await deleteUsers(ids);
table.resetRowSelection();
};
const handleBulkExport = () => {
const data = selectedRows.map(row => row.original);
exportToCSV(data, 'selected-users.csv');
};
if (selectedCount === 0) return null;
return (
<div className="flex gap-2">
<Badge>{selectedCount} selected</Badge>
<Button onClick={handleBulkExport}>Export</Button>
<Button variant="destructive" onClick={handleBulkDelete}>
Delete
</Button>
</div>
);
}<ActiveGrid
columns={columns}
data={data}
toolbar={{
actions: (table) => {
const selectedCount = table.getSelectedRowModel().rows.length;
if (selectedCount === 0) {
return <Button>Add User</Button>;
}
return (
<div className="flex gap-2 items-center">
<span>{selectedCount} selected</span>
<Button onClick={() => handleBulk(table.getSelectedRowModel().rows)}>
Bulk Action
</Button>
<Button variant="ghost" onClick={() => table.resetRowSelection()}>
Clear
</Button>
</div>
);
},
}}
{...}
/>import { useState } from 'react';
import { getSelectionColumn } from '@workspace/active-grid';
import { RowSelectionState } from '@tanstack/react-table';
type User = {
id: string;
name: string;
email: string;
status: 'active' | 'inactive';
};
function UsersTable() {
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const columns = [
getSelectionColumn<User>(),
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
{ accessorKey: 'status', header: 'Status' },
];
const handleBulkDelete = async (table: Table<User>) => {
const selectedRows = table.getSelectedRowModel().rows;
const ids = selectedRows.map(row => row.original.id);
await deleteUsers(ids);
table.resetRowSelection();
};
return (
<ActiveGrid
columns={columns}
data={users}
state={{ rowSelection }}
onRowSelectionChange={setRowSelection}
enableRowSelection={(row) => row.original.status === 'active'}
getRowId={(row) => row.id}
toolbar={{
actions: (table) => {
const count = table.getSelectedRowModel().rows.length;
if (count === 0) return null;
return (
<div className="flex gap-2">
<Badge>{count} selected</Badge>
<Button onClick={() => handleBulkDelete(table)}>
Delete Selected
</Button>
</div>
);
},
}}
/>
);
}import { Checkbox } from '@workspace/ui';
function CustomSelectionCell({ row }) {
return (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
className="custom-checkbox"
/>
);
}.grid-row[data-state='selected'] {
background-color: hsl(var(--primary) / 0.1);
}import { RowSelectionState, Table } from '@tanstack/react-table';
import { getSelectionColumn } from '@workspace/active-grid';
type User = {
id: string;
name: string;
};
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
const columns: GridColumnDef<User>[] = [
getSelectionColumn<User>(),
// ... other columns
];
const handleBulkAction = (table: Table<User>) => {
const selectedData: User[] = table
.getSelectedRowModel()
.rows
.map(row => row.original);
// Process selected data
};