Row sorting
Sorting is a feature you opt into. Try it live - click any column
header to cycle none → asc → desc → none; shift-click adds the
column to the sort key list (multi-sort):
Open the live example: Sort, filter, paginate (Filtering & Search)
The examples on this page run against these rows:
<script lang="ts">
import { SvGrid } from '@svgrid/grid'
type Person = {
id: number
name: string
email: string
department: string
age: number
salary: number
city: string
startDate: string
active: boolean
}
const people: Person[] = [
{ id: 1, name: 'Ada Lovelace', email: '[email protected]', department: 'Engineering', age: 36, salary: 142000, city: 'London', startDate: '2021-03-01', active: true },
{ id: 2, name: 'Grace Hopper', email: '[email protected]', department: 'Engineering', age: 45, salary: 168000, city: 'New York', startDate: '2019-07-15', active: true },
{ id: 3, name: 'Linus Torvalds', email: '[email protected]', department: 'Platform', age: 54, salary: 155000, city: 'Portland', startDate: '2020-01-20', active: false },
{ id: 4, name: 'Radia Perlman', email: '[email protected]', department: 'Networking', age: 49, salary: 161000, city: 'Seattle', startDate: '2022-09-05', active: true },
{ id: 5, name: 'Barbara Liskov', email: '[email protected]', department: 'Platform', age: 52, salary: 172000, city: 'Boston', startDate: '2018-11-11', active: true },
]
const data = people
</script>
<script lang="ts">
import {
SvGrid, tableFeatures, rowSortingFeature, type ColumnDef,
} from '@svgrid/grid'
const features = tableFeatures({ rowSortingFeature })
const columns: ColumnDef<typeof features, Person>[] = [
{ field: 'firstName', header: 'First name', editorType: 'text' },
{ field: 'age', header: 'Age', editorType: 'number' },
{ field: 'joinedAt', header: 'Joined', editorType: 'date' },
]
</script>
<SvGrid {data} {columns} features={features} />
Clicking a sortable header toggles none → asc → desc → none. Shift-click
adds the column to the sort key list (multi-sort).
Sort functions
sortFns exposes the built-in comparators:
import { sortFns } from '@svgrid/grid'
// sortFns.auto - blanks, then numbers numerically, then text (default for unknown types)
// sortFns.number - numeric; blanks and non-numeric values ('n/a') first
// sortFns.date - Date-parsed; blanks and invalid dates first
All three sort blanks (null, undefined, '') first ascending and last
descending, and never return NaN, so a column with placeholder text still
sorts into a consistent order.
The grid picks the comparator based on the column's editorType:
| editorType | comparator |
|---|---|
'number' |
sortFns.number |
'date' | 'datetime' |
sortFns.date |
| anything else | sortFns.auto |
If your column has a non-trivial type, set editorType even if you do not
want inline editing - it is what tells sort and filter how to behave.
Sort by a rank
A status column sorted as text puts "Done" before "To do". sortValue gives
the number to sort a value by instead, and grouped rows follow it too:
const STATUS = ['To do', 'In progress', 'Done']
const columns = [
{ field: 'status', header: 'Status', sortValue: (v: unknown) => STATUS.indexOf(String(v)) },
]
Blanks, and anything that is not a number, sort first ascending, as in a number column.
Your own comparator
sortComparator compares two of a column's values in place of the built-in
order. It also gets the direction being sorted, desc. The grid reverses your
result for a descending sort, so return the ascending order; desc is there
for a value you want held at one end both ways. sortValue wins when a column
sets both.
const columns = [
{ field: 'code', header: 'Code', sortComparator: (a, b) => String(a).length - String(b).length },
]
Keep blanks at one end (Enterprise)
@svgrid/enterprise ships comparators that hold blank cells at the bottom or
the top in both directions, so tasks with no due date stay below the dated
ones whichever way Due runs. The other values sort as the grid sorts them
(setup):
// blanksLast is exported by @svgrid/enterprise
const columns = [
{ field: 'due', header: 'Due', cellDataType: 'dateString', sortComparator: blanksLast('date') },
]
blanksFirst holds them at the top. Pass 'number', 'date' or 'auto'
(the default) for how the other values compare.
Programmatic sort
api.setSort('age', 'desc') // sort by age descending
api.setSort('age', null) // clear sort on this column
api.clearSort() // clear all sort
setSort replaces any existing sort with a single clause. For
multi-column sort, the user clicks the second column header with
Shift held (the in-grid affordance). A multi-sort setter on the API
is tracked in Missing features.
To observe sort changes from outside the grid:
<SvGrid
data={rows}
columns={columns}
features={features}
onSortingChange={(next) => (sorting = next)}
/>
Disable sort per column
Not yet first-class - there is no enableSorting: false field. To
prevent a column from being sortable, omit rowSortingFeature from
tableFeatures(...), or render a custom header via header: () => renderSnippet(...) that doesn't bind to the sort button.
Sorting + server-side data
When sort happens on the backend, pair externalSort={true} with
onSortingChange and round-trip the sort clauses through your
fetcher. See the 09-server-side demo.
Multi-column sort
Shift-click a second header and the sort becomes ordered: department first, then salary within it. The order you click is the order applied, which is why the header shows a position number once more than one is active.
<script lang="ts">
import { SvGrid, type GridColumns, type SvGridApi } from '@svgrid/grid'
type Person = {
id: number
name: string
department: string
city: string
salary: number
bio: string
}
const seed: Person[] = [
{ id: 1, name: 'Ada Lovelace', department: 'Engineering', city: 'London', salary: 142000,
bio: 'Wrote the first algorithm intended for a machine, and the first account of what a general-purpose computer could do beyond arithmetic.' },
{ id: 2, name: 'Grace Hopper', department: 'Engineering', city: 'New York', salary: 168000,
bio: 'Built the first compiler and argued that programs should be written in something closer to English than to machine code.' },
{ id: 3, name: 'Linus Torvalds', department: 'Platform', city: 'Portland', salary: 155000,
bio: 'Wrote a kernel and, later, the version control system that most of the industry now runs on.' },
]
const columns: GridColumns<Person> = [
{ field: 'department', header: 'Department', width: 170 },
{ field: 'name', header: 'Name', width: 180 },
{ field: 'salary', header: 'Salary', width: 140,
format: { type: 'currency', currency: 'USD' } },
]
</script>
<SvGrid data={seed} {columns} sortable />
Reading the sort model
onSortingChange reports the model as an ordered array, which is exactly the
shape you persist to a URL or hand to a server.
<script lang="ts">
import { SvGrid, type GridColumns, type SvGridApi } from '@svgrid/grid'
type Person = {
id: number
name: string
department: string
city: string
salary: number
bio: string
}
const seed: Person[] = [
{ id: 1, name: 'Ada Lovelace', department: 'Engineering', city: 'London', salary: 142000,
bio: 'Wrote the first algorithm intended for a machine, and the first account of what a general-purpose computer could do beyond arithmetic.' },
{ id: 2, name: 'Grace Hopper', department: 'Engineering', city: 'New York', salary: 168000,
bio: 'Built the first compiler and argued that programs should be written in something closer to English than to machine code.' },
{ id: 3, name: 'Linus Torvalds', department: 'Platform', city: 'Portland', salary: 155000,
bio: 'Wrote a kernel and, later, the version control system that most of the industry now runs on.' },
]
let model = $state('[]')
const columns: GridColumns<Person> = [
{ field: 'name', header: 'Name', width: 190 },
{ field: 'city', header: 'City', width: 150 },
{ field: 'salary', header: 'Salary', width: 140,
format: { type: 'currency', currency: 'USD' } },
]
</script>
<SvGrid
data={seed}
{columns}
sortable
onSortingChange={(s) => (model = JSON.stringify(s))}
/>
<p>Sort model: <code>{model}</code></p>
See also
Live examples
- Sort, filter, paginate - Three most-asked-for features wired together against ~5k rows.
- Server-side data - Sort/filter/page round-tripped to a mock endpoint with debounce + cancel.
Related articles
- Inside SvGrid: The Row Model and Sorting - How sorting shaped SvGrid's row-model pipeline - the decisions made early that every later feature inherited.
- Multi-Column Sorting in a Svelte Data Grid - How multi-column sorting works in SvGrid, from click behavior and sort priority to server-side ordering and programmatic control via the API.