Skip to main content

Sorting

Click a column header to sort. Click again to reverse. Use Clear sort in the column menu to remove it. An arrow shows the current direction. That's the whole interaction — no configuration beyond sortable: true.

Click any column header to sort
Live
Try it with Fluent UI

The demo uses Radix UI styling. Switch the import to @alaarab/ogrid-react-fluent and the sort indicator renders in the Fluent UI v9 style — no other code changes.

Make a column sortable​

Add sortable: true to any column definition:

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}
/>
);
}
Switching UI libraries

Same props across all React packages — 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>

Set a default sort​

Use defaultSortBy and defaultSortDirection to pre-sort the grid on mount — useful when there's an obvious "right" order for your data, like newest-first for a log or alphabetical for a directory:

<OGrid
columns={columns}
data={employees}
getRowId={(item) => item.id}
defaultSortBy="name"
defaultSortDirection="asc"
/>

Custom sort order​

By default, text columns sort alphabetically and numeric columns sort numerically. When that isn't right — priority levels, custom status orderings, anything domain-specific — provide a compare function:

const columns = [
{
columnId: 'priority',
name: 'Priority',
sortable: true,
// "High" should sort before "Medium" which sorts before "Low"
compare: (a, b) => {
const order = { High: 0, Medium: 1, Low: 2 };
return order[a.priority] - order[b.priority];
},
},
{
columnId: 'status',
name: 'Status',
sortable: true,
// Custom business logic: "In Progress" first, then "Open", then "Closed"
compare: (a, b) => {
const order = { 'In Progress': 0, Open: 1, Closed: 2 };
return (order[a.status] ?? 99) - (order[b.status] ?? 99);
},
},
];
Pro tip

Custom compare functions receive the full row objects — not just the cell values. That means you can sort by computed values, nested fields, or anything else you can derive from the row.

Keep sort state in your app​

If you need to sync sort state to the URL, read it from an API, or share it between components, use controlled mode:

function App() {
const [sort, setSort] = useState({ field: 'name', direction: 'asc' as const });

// Persist to URL:
// useEffect(() => { setSearchParam('sort', sort.field); }, [sort]);

return (
<OGrid
columns={columns}
data={people}
getRowId={(item) => item.id}
sort={sort}
onSortChange={setSort}
/>
);
}

When sort and onSortChange are both present, the grid is fully controlled — it never manages sort state internally.

Server-side sorting​

Sending sort state to your API is straightforward. The grid passes sort info to fetchPage() — your server does the actual ordering:

const dataSource: IDataSource<Project> = {
fetchPage: async ({ sort, page, pageSize, filters }) => {
const params = new URLSearchParams({
page: String(page),
pageSize: String(pageSize),
});

// Wire sort directly to your query params or request body
if (sort) {
params.set('sortBy', sort.field);
params.set('sortDir', sort.direction); // 'asc' | 'desc'
}

const res = await fetch(`/api/projects?${params}`);
const json = await res.json();
return { items: json.data, totalCount: json.total };
},
};
Pro tip

Server-side sorting disables client-side sort entirely — the grid just re-fetches when the user clicks a header. This pairs perfectly with large datasets where you never want all rows in the browser at once. See Server-Side Data for the full setup.

Props reference​

PropTypeDefaultDescription
sortablebooleanfalseSet on IColumnDef. Enables click-to-sort on that column header.
compare(a: T, b: T) => number—Custom sort comparator on IColumnDef. Receives full row objects.
sort{ field: string; direction: 'asc' | 'desc' }—Controlled sort state on OGrid.
onSortChange(sort) => void—Called when the user changes the sort. Required for controlled mode.
defaultSortBystring—Initial sort column (uncontrolled only).
defaultSortDirection'asc' | 'desc''asc'Initial sort direction (uncontrolled only).

Next steps​