Sorting
Add sortable columns to your grid with a single prop. Users click a column header to cycle through ascending, descending, and unsorted states. A sort indicator arrow shows the current direction.
Live Demo
The demo above uses Radix UI for styling. To see this feature with your framework's design system (Fluent UI, Material UI, Vuetify, PrimeNG, etc.), click "Open in online demo" below the demo.
Quick Example
- React
- Angular
- Vue
- Vanilla JS
import { OGrid } from '@alaarab/ogrid-react-radix';
const columns = [
{ columnId: 'name', name: 'Name', sortable: true },
{ columnId: 'age', name: 'Age', sortable: true, type: 'numeric' as const },
{ columnId: 'department', name: 'Department', sortable: true },
{
columnId: 'salary',
name: 'Salary',
sortable: true,
type: 'numeric' as const,
valueFormatter: (v) => `$${Number(v).toLocaleString()}`,
},
];
function App() {
return (
<OGrid
columns={columns}
data={people}
getRowId={(item) => item.id}
defaultPageSize={10}
/>
);
}
The OGrid component has the same props across all React UI packages. To switch, just change the import:
- Radix (lightweight, default):
from '@alaarab/ogrid-react-radix' - Fluent UI (Microsoft 365 / SPFx):
from '@alaarab/ogrid-react-fluent'— wrap in<FluentProvider> - Material UI (MUI v7):
from '@alaarab/ogrid-react-material'— wrap in<ThemeProvider>
import { Component } from '@angular/core';
import { OGridComponent, type IColumnDef } from '@alaarab/ogrid-angular-material';
@Component({
standalone: true,
imports: [OGridComponent],
template: `<ogrid [props]="gridProps" />`
})
export class GridComponent {
gridProps = {
columns: [
{ columnId: 'name', name: 'Name', sortable: true },
{ columnId: 'age', name: 'Age', sortable: true, type: 'numeric' },
{ columnId: 'department', name: 'Department', sortable: true },
{
columnId: 'salary',
name: 'Salary',
sortable: true,
type: 'numeric',
valueFormatter: (v: unknown) => `$${Number(v).toLocaleString()}`,
},
] as IColumnDef<Person>[],
data: people,
getRowId: (item: Person) => item.id,
defaultPageSize: 10,
};
}
Same component API across Angular packages. To switch, just change the import:
- Radix (CDK):
from '@alaarab/ogrid-angular-radix'(default, lightweight) - Angular Material:
from '@alaarab/ogrid-angular-material' - PrimeNG:
from '@alaarab/ogrid-angular-primeng'
All components are standalone — no NgModule required.
<script setup lang="ts">
import { OGrid, type IColumnDef } from '@alaarab/ogrid-vue-vuetify';
const columns: IColumnDef<Person>[] = [
{ columnId: 'name', name: 'Name', sortable: true },
{ columnId: 'age', name: 'Age', sortable: true, type: 'numeric' },
{ columnId: 'department', name: 'Department', sortable: true },
{
columnId: 'salary',
name: 'Salary',
sortable: true,
type: 'numeric',
valueFormatter: (v) => `$${Number(v).toLocaleString()}`,
},
];
const gridProps = {
columns,
data: people,
getRowId: (item) => item.id,
defaultPageSize: 10,
};
</script>
<template>
<OGrid :gridProps="gridProps" />
</template>
Same component API across Vue packages. To switch, just change the import:
- Radix (Headless UI):
from '@alaarab/ogrid-vue-radix'(default, lightweight) - Vuetify:
from '@alaarab/ogrid-vue-vuetify'— wrap in<v-app>for theming - PrimeVue:
from '@alaarab/ogrid-vue-primevue'
import { OGrid } from '@alaarab/ogrid-js';
import '@alaarab/ogrid-js/styles';
const grid = new OGrid(document.getElementById('grid'), {
columns: [
{ columnId: 'name', name: 'Name', sortable: true },
{ columnId: 'age', name: 'Age', sortable: true, type: 'numeric' },
{ columnId: 'department', name: 'Department', sortable: true },
{
columnId: 'salary',
name: 'Salary',
sortable: true,
type: 'numeric',
valueFormatter: (v) => `$${Number(v).toLocaleString()}`,
},
],
data: people,
getRowId: (item) => item.id,
pageSize: 10,
});
How It Works
Set sortable: true on any column definition to make it sortable. When a user clicks the column header, OGrid toggles the sort direction: unsorted, ascending, then descending.
OGrid supports both uncontrolled and controlled sorting:
- Uncontrolled -- the grid manages sort state internally. Use
defaultSortByanddefaultSortDirectionto set the initial sort. - Controlled -- you own the state. Pass
sortandonSortChangeto the grid.
Custom Comparator
For columns that need custom sort logic (e.g., sorting by a nested field or special ordering), provide a compare function on the column definition:
const columns = [
{
columnId: 'priority',
name: 'Priority',
sortable: true,
compare: (a, b) => {
const order = { High: 0, Medium: 1, Low: 2 };
return order[a.priority] - order[b.priority];
},
},
];
Server-Side Sorting
When using a dataSource, the sort parameter is forwarded to fetchPage(). The grid does not sort the data itself -- your server handles it:
const dataSource: IDataSource<Project> = {
fetchPage: async ({ sort, page, pageSize, filters }) => {
const res = await fetch(`/api/projects?sort=${sort?.field}&dir=${sort?.direction}&page=${page}`);
const json = await res.json();
return { items: json.data, totalCount: json.total };
},
};
Controlled Example
function App() {
const [sort, setSort] = useState({ field: 'name', direction: 'asc' as const });
return (
<OGrid
columns={columns}
data={people}
getRowId={(item) => item.id}
sort={sort}
onSortChange={setSort}
/>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
sortable | boolean | false | Set on IColumnDef to enable sorting for that column. |
compare | (a: T, b: T) => number | -- | Custom sort comparator on IColumnDef. |
sort | { field: string; direction: 'asc' | 'desc' } | -- | Controlled sort state on OGrid. |
onSortChange | (sort: { field: string; direction: 'asc' | 'desc' }) => void | -- | Called when sort changes (controlled mode). |
defaultSortBy | string | -- | Initial sort column (uncontrolled mode). |
defaultSortDirection | 'asc' | 'desc' | 'asc' | Initial sort direction (uncontrolled mode). |
Related
- Filtering -- filter rows by column values
- Pagination -- paginate sorted results