Selection Patterns
Common patterns for implementing cell selection in your data grid.
Single Cell Selection
The simplest selection mode. Click to select one cell at a time:
tsx
const grid = useGridBehavior({
rows,
columns,
config: {
selection: { mode: "single" },
},
});Range Selection
Select rectangular regions of cells:
tsx
const grid = useGridBehavior({
rows,
columns,
config: {
selection: { mode: "range" },
},
});Keyboard Shortcuts
| Shortcut | Action |
|---|---|
| Click | Select single cell |
| Shift+Click | Extend selection to clicked cell |
| Shift+Arrow | Extend selection by one cell |
| Ctrl+A | Select all cells |
| Escape | Clear selection |
Row Selection with Checkboxes
For row-level selection, add a checkbox column:
tsx
const columns = [
{
id: "select",
header: ({ table }) => (
<input
type="checkbox"
checked={table.getIsAllRowsSelected()}
onChange={table.getToggleAllRowsSelectedHandler()}
/>
),
cell: ({ row }) => (
<input
type="checkbox"
checked={row.getIsSelected()}
onChange={row.getToggleSelectedHandler()}
/>
),
},
// ... other columns
];Visual Feedback
Style selected cells for clear feedback:
tsx
function Cell({ grid, rowId, colId, children }) {
const cell = useCellBehavior(grid, rowId, colId);
return (
<div
{...cell.props}
className={cn(
"border border-transparent",
cell.isFocused && "ring-2 ring-blue-500",
cell.isSelected && "bg-blue-50 border-blue-200",
cell.isFocused && cell.isSelected && "bg-blue-100",
)}
>
{children}
</div>
);
}Selection Bounds Indicator
Show a border around the entire selection:
tsx
function SelectionOverlay({ grid }) {
const bounds = useStore(grid.store, selectSelectionBounds);
if (!bounds) return null;
// Calculate pixel positions from bounds
const style = {
position: "absolute",
top: bounds.startRow * rowHeight,
left: bounds.startCol * colWidth,
width: (bounds.endCol - bounds.startCol + 1) * colWidth,
height: (bounds.endRow - bounds.startRow + 1) * rowHeight,
border: "2px solid blue",
pointerEvents: "none",
};
return <div style={style} />;
}Selection Change Callback
React to selection changes:
tsx
const grid = useGridBehavior({
rows,
columns,
onSelectionChange: ({ ranges }) => {
// ranges is an array of { start, end } cell references
const selectedCells = calculateSelectedCells(ranges);
console.log("Selected:", selectedCells);
// Example: update external state
setSelectedData(
selectedCells.map(({ rowId, colId }) => data.find((row) => row.id === rowId)?.[colId]),
);
},
});Copy Selection to Clipboard
Handle Ctrl+C to copy selected data:
tsx
const grid = useGridBehavior({
rows,
columns,
config: {
clipboard: {
serialize: (cells) => {
// Custom serialization
return cells.map((row) => row.map((cell) => cell.value).join("\t")).join("\n");
},
},
},
});Clear Selection on Navigation
Optionally clear selection when navigating without Shift:
tsx
const grid = useGridBehavior({
rows,
columns,
config: {
selection: {
mode: "range",
clearOnNavigation: true, // Arrow keys clear selection
},
},
});Programmatic Selection
Select cells programmatically:
tsx
function SelectAll({ grid }) {
const handleSelectAll = () => {
grid.dispatch({ type: "SELECT_ALL" });
};
const handleClearSelection = () => {
grid.dispatch({ type: "CLEAR_SELECTION" });
};
const handleSelectRange = () => {
grid.dispatch({
type: "SELECT_RANGE",
start: { rowId: "row-0", colId: "col-0" },
end: { rowId: "row-5", colId: "col-2" },
});
};
return (
<div>
<button onClick={handleSelectAll}>Select All</button>
<button onClick={handleClearSelection}>Clear</button>
<button onClick={handleSelectRange}>Select Range</button>
</div>
);
}Selection Persistence
Selection persists when focus leaves the grid. This enables:
- Context menu operations on selection
- Copy/paste after clicking elsewhere
- Multi-step workflows
To explicitly clear:
tsx
// Clear on blur (not recommended, but possible)
const grid = useGridBehavior({
rows,
columns,
onBlur: () => {
grid.dispatch({ type: "CLEAR_SELECTION" });
},
});See Also
- Behaviors Spec — Full selection specification
- TanStack Integration — Complete integration guide