Sorting
Sort rows by one or more columns. Click a header to cycle through ascending, descending, and unsorted. Hold Shift to add multi-column sorts.
How to Enable
Sorting is enabled by default at the table level (enableSorting: true). Enable it per column:
columnHelper.accessor('name', {
header: 'Name',
enableSorting: true,
})
Table Options
| Option | Type | Default | Description |
|---|---|---|---|
enableSorting | boolean | true | Enable/disable sorting globally |
enableMultiSort | boolean | true | Allow sorting by multiple columns |
enableSortingRemoval | boolean | true | Allow removing sort (third click) |
maxMultiSortColCount | number | Infinity | Max simultaneous sort columns |
manualSorting | boolean | false | If true, sorting is handled externally (server-side) |
sortDescFirst | boolean | false | Start with descending on first click |
isMultiSortEvent | (e) => boolean | Shift key | Which modifier key triggers multi-sort |
onSortingChange | OnChangeFn<SortingState> | -- | Callback when sorting state changes |
postSortRows | (rows) => Row[] | void | -- | Reorder the final sorted rows before render (AG-parity) |
Column Options
| Option | Type | Default | Description |
|---|---|---|---|
enableSorting | boolean | true | Enable sorting for this column |
sortingFn | SortingFnOption | 'auto' | Sort function name or custom function |
sortDescFirst | boolean | false | Start descending for this column |
invertSorting | boolean | false | Invert sort direction |
sortUndefined | false | -1 | 1 | 'first' | 'last' | -- | Where to place undefined values |
Built-in Sorting Functions
| Name | Description |
|---|---|
alphanumeric | Natural sort -- "item2" before "item10" (case-insensitive) |
alphanumericCaseSensitive | Natural sort (case-sensitive) |
text | Locale-aware string comparison (case-insensitive) |
textCaseSensitive | Locale-aware string comparison (case-sensitive) |
datetime | Sorts Date objects and date strings by timestamp |
basic | Simple > / < comparison for numbers and strings |
Custom Sort Function
columnHelper.accessor('priority', {
header: 'Priority',
sortingFn: (rowA, rowB, columnId) => {
const order = { high: 3, medium: 2, low: 1 }
const a = order[rowA.getValue<string>(columnId)] ?? 0
const b = order[rowB.getValue<string>(columnId)] ?? 0
return a - b
},
})
Post-sort hook
postSortRows runs after the sorted row model is built and lets you reorder the
final rows before render — the AG Grid postSortRows equivalent. Return a new
array or mutate the given one in place. It runs on every sort (and with no
active sort), so it is the right place to keep child rows under their parents:
const table = useTable({
data,
columns,
postSortRows: (rows) => {
const pinned = rows.filter((r) => r.original.pinned)
const rest = rows.filter((r) => !r.original.pinned)
return [...pinned, ...rest]
},
})
postSortRows is skipped under manualSorting.
Programmatic Control
// Set sorting
table.setSorting([{ id: 'name', desc: false }])
// Add a sort column
table.setSorting((prev) => [...prev, { id: 'age', desc: true }])
// Reset to no sorting
table.resetSorting(true)
// Toggle sort on a specific column
table.getColumn('name')?.toggleSorting()
// Check if a column is sorted
const direction = table.getColumn('name')?.getIsSorted() // 'asc' | 'desc' | false