# Data table: Sorting and selection

> Sort the slotsmith data table by one or more columns, and select rows with checkboxes, controlled or uncontrolled, with a rule for rows that cannot be selected.

The data table sorts when you click a column header and selects rows with a checkbox column. Sorting is on by default; pass `enableRowSelection` to add the checkboxes, and `selection` with `onSelectionChange` to read the selected rows.

```tsx
import { useState } from "react";
import { DataTable, type DataTableColumnDef, type DataTableSortingState } from "slotsmith/data-table";
import { people, type Person } from "../shared/people";

const columns: DataTableColumnDef<Person>[] = [
  { accessorKey: "name", header: "Name" },
  { accessorKey: "role", header: "Role" },
  { accessorKey: "team", header: "Team" },
  // A column that should not sort opts out.
  { accessorKey: "status", header: "Status", enableSorting: false },
];

const rows = people.slice(0, 6);

export default function SortingAndSelection() {
  const [sorting, setSorting] = useState<DataTableSortingState>([]);
  const [selection, setSelection] = useState<Person[]>([]);
  return (
    <>
      <DataTable
        data={rows}
        columns={columns}
        getRowId={(person) => person.id}
        sorting={sorting}
        onSortingChange={setSorting}
        // Shift-click a second header to sort by both columns.
        enableMultiSort
        // People on leave cannot be selected: their checkbox is disabled.
        enableRowSelection={(row) => row.original.status !== "On leave"}
        selection={selection}
        onSelectionChange={setSelection}
        enablePagination={false}
      />
      <p>
        {sorting.length === 0
          ? "Not sorted."
          : `Sorted by: ${sorting.map((sort) => `${sort.id} ${sort.desc ? "descending" : "ascending"}`).join(", ")}`}
      </p>
      <p>{selection.length === 0 ? "No rows selected." : `Selected: ${selection.map((person) => person.name).join(", ")}`}</p>
    </>
  );
}
```

Click a header to sort it ascending; click again for descending, and a third time to clear. Shift-click a second header to add it to the sort. Tick rows to select them: the text under the table lists them. Chloe Martin is on leave, so her checkbox is disabled.

## Sorting

Every data column, one with an `accessorKey` or `accessorFn`, sorts unless its definition sets `enableSorting: false`, as the Status column does. A display column, such as one that only holds buttons, has no value to sort by and never sorts. The header holds a button, and its `<th>` carries `aria-sort`, so screen readers announce the order.

- [`sorting`](https://slotsmith.dev/components/data-table/api/#props) and [`onSortingChange`](https://slotsmith.dev/components/data-table/api/#props) control the sort. The state is a list of `{ id, desc }`, one per sorted column, in priority order. Leave them out and use [`defaultSorting`](https://slotsmith.dev/components/data-table/api/#props) for a starting sort the table keeps itself.
- [`enableMultiSort`](https://slotsmith.dev/components/data-table/api/#props) lets shift-click add columns to the sort.
- Each column sorts ascending first. Set `sortDescFirst: true` in a column definition to start that column descending, as you might for numbers and dates.
- [`manualSorting`](https://slotsmith.dev/components/data-table/api/#props) says the rows arrive already sorted, for sorting on the server; the table then only reports the clicks. The [server data](https://slotsmith.dev/components/data-table/guides/server-data/) guide sorts this way.

The header button and the arrow are the [`SortTrigger`](https://slotsmith.dev/components/data-table/api/#slot-SortTrigger) and [`SortIcon`](https://slotsmith.dev/components/data-table/api/#slot-SortIcon) slots, so a design system's own can replace them.

## Selection

[`enableRowSelection`](https://slotsmith.dev/components/data-table/api/#props) adds a checkbox to each row and a select-all checkbox to the header. Given a function, it decides per row: here, rows whose status is "On leave" cannot be selected.

- [`selection`](https://slotsmith.dev/components/data-table/api/#props) and [`onSelectionChange`](https://slotsmith.dev/components/data-table/api/#props) control the selection as row objects, matched to rows by `getRowId`. [`defaultSelection`](https://slotsmith.dev/components/data-table/api/#props) sets a starting selection instead.
- The header checkbox selects every selectable row on the current page, and is indeterminate while only some are selected.
- [`resetSelectionOnPageChange`](https://slotsmith.dev/components/data-table/api/#props) clears the selection when the page or the page size changes.

Give rows a stable id with [`getRowId`](https://slotsmith.dev/components/data-table/api/#props), so a selection survives re-sorting and new data. The checkboxes are the [`Checkbox`](https://slotsmith.dev/components/data-table/api/#slot-Checkbox) slot, named by the [`selectRow`](https://slotsmith.dev/components/data-table/api/#label-selectRow) and [`selectAll`](https://slotsmith.dev/components/data-table/api/#label-selectAll) labels.
