Skip to main content

Column Groups

Group related columns under shared parent headers. OGrid supports arbitrarily nested column groups that render as multi-row <thead> headers.

Live Demo

Column headers are grouped into 'Personal Info' and 'Employment'
Live
Try it in your framework

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

import { OGrid } from '@alaarab/ogrid-react-radix';
import type { IColumnDef, IColumnGroupDef } from '@alaarab/ogrid-react-radix';

interface Person {
id: number;
name: string;
age: number;
email: string;
department: string;
salary: number;
status: string;
}

const columns: (IColumnDef<Person> | IColumnGroupDef<Person>)[] = [
{
headerName: 'Personal Info',
children: [
{ columnId: 'name', name: 'Name' },
{ columnId: 'age', name: 'Age', type: 'numeric' },
{ columnId: 'email', name: 'Email' },
],
},
{
headerName: 'Employment',
children: [
{ columnId: 'department', name: 'Department' },
{
columnId: 'salary',
name: 'Salary',
type: 'numeric',
valueFormatter: (v) => `$${Number(v).toLocaleString()}`,
},
{ columnId: 'status', name: 'Status' },
],
},
];

function App() {
return (
<OGrid
columns={columns}
data={people}
getRowId={(p) => p.id}
defaultPageSize={10}
/>
);
}
Switching UI libraries

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>

This renders a two-row header: the first row shows "Personal Info" spanning three columns and "Employment" spanning three columns, with the individual column names in the second row.

How It Works

Column groups use the IColumnGroupDef<T> type. A group has a headerName (the text displayed in the group header cell) and a children array that can contain either IColumnDef items or nested IColumnGroupDef items.

// IColumnGroupDef<T>
{
headerName: string;
children: (IColumnGroupDef<T> | IColumnDef<T>)[];
}

When the columns prop contains groups, OGrid internally calls buildHeaderRows() to produce a multi-row header model. Each group header cell spans the correct number of leaf columns via colSpan.

Nested Groups

Groups can be nested to any depth. Each level adds another header row.

const columns: (IColumnDef<Row> | IColumnGroupDef<Row>)[] = [
{
headerName: 'Contact',
children: [
{
headerName: 'Name',
children: [
{ columnId: 'firstName', name: 'First' },
{ columnId: 'lastName', name: 'Last' },
],
},
{ columnId: 'email', name: 'Email' },
],
},
{ columnId: 'role', name: 'Role' },
];

This produces three header rows:

Contact (span 3)Role (span 1, rowSpan 3)
Name (span 2)Email (rowSpan 2)
FirstLast

Mixing Groups and Standalone Columns

Standalone IColumnDef items at the top level are valid alongside groups. They span all header rows vertically.

Group Header Behavior

Group headers are display-only:

  • Not sortable. Clicking a group header does nothing.
  • Not filterable. No filter icon or popover appears on group headers.
  • Not resizable. Group headers cannot be dragged to resize.
  • Centered text. Group header labels are centered over their children by default.

Sorting, filtering, and resizing remain available on the leaf column headers beneath the groups.

Props Reference

TypeFieldDescription
IColumnGroupDef<T>headerNameDisplay text for the group header
IColumnGroupDef<T>childrenArray of child columns or nested groups
IOGridProps<T>columnsAccepts (IColumnDef<T> | IColumnGroupDef<T>)[]