

<Preview className="relative" name="SimpleDataTableSelectionExample" />

`DataTable` supports two selection modes:

| Mode                    | Best For                                         | Requirements                                          |
| ----------------------- | ------------------------------------------------ | ----------------------------------------------------- |
| Built-in selection      | Local table state with a simple `selected` field | Rows include `selected`; pass `onDataChange`          |
| Controlled id selection | Remote data, virtualization, persisted selection | Pass `getRowId`, `selection`, and `onSelectionChange` |

### Built-in Selection [#built-in-selection]

Built-in selection is the shortest path when the table owns the row array and each row can carry a `selected` field.

```tsx
const [employees, setEmployees] = useState(
  sampleEmployees.map((employee) => ({ ...employee, selected: false })),
);

<DataTable
  data={employees}
  columns={selectionColumns}
  enableRowSelection
  onDataChange={setEmployees}
/>
```

### Controlled Id-based Selection [#controlled-id-based-selection]

Use controlled selection when row data comes from a server, a cache, or another store that should not be mutated by the table.

```tsx
const [employees] = useState(sampleEmployees);
const [selection, setSelection] = useState<RowSelectionState>({});

<DataTable
  data={employees}
  columns={selectionColumns}
  enableRowSelection
  getRowId={(employee) => employee.id}
  selection={selection}
  onSelectionChange={setSelection}
/>
```

Stable row ids matter here. Without `getRowId`, TanStack falls back to row indexes, which are fragile once sorting, filtering, or virtualization enter the picture.

## Bulk Actions [#bulk-actions]

`SelectionToolbar` is a primitive, but it composes naturally with `DataTable` selection state for bulk actions.

<Tabs className="bg-transparent border-none rounded-none" items="['Preview', 'Code']">
  <Tab value="Preview" className="p-0">
    <Preview className="relative" name="BulkActionsDataTableSelectionExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    function SelectableTableWithBulkActions() {
      const [employees, setEmployees] = useState(
        sampleEmployees.map((employee) => ({ ...employee, selected: false })),
      );
      const selectedCount = employees.filter((employee) => employee.selected).length;

      return (
        <div className="relative">
          <DataTable
            data={employees}
            columns={selectionColumns}
            enableRowSelection
            onDataChange={setEmployees}
          />

          <SelectionToolbar
            actions={actions}
            onClear={() => {
              setEmployees((current) =>
                current.map((employee) => ({ ...employee, selected: false })),
              );
            }}
            position="container"
            selectedCount={selectedCount}
            totalCount={employees.length}
          />
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

For controlled id-based selection, derive `selectedCount` from the selection map instead of the row objects.

## API Reference [#api-reference]

| Prop                           | Type                                     | Default | Description                                  |
| ------------------------------ | ---------------------------------------- | ------- | -------------------------------------------- |
| `enableRowSelection`           | `boolean`                                | `false` | Add the selection checkbox column            |
| `selection`                    | `RowSelectionState`                      | -       | Controlled id-based selection state          |
| `onSelectionChange`            | `(selection: RowSelectionState) => void` | -       | Controlled selection change handler          |
| `onDataChange`                 | `(data: TData[]) => void`                | -       | Required for built-in selection mode         |
| `getRowId`                     | `(row: TData, index: number) => string`  | -       | Stable ids for controlled selection          |
| `clearSelectionOnOutsideClick` | `boolean`                                | `false` | Clear the current selection on outside click |
