Column groups

A column group is a ColumnDef whose columns array contains children. The parent renders a spanning header above its children. The pivot demo below shows three levels of grouped headers in action - Year wraps Quarter wraps measure:

Open the live example: Pivot - Table + Designer (Pivot Grid)

The examples on this page run against these rows:

<script lang="ts">
  import { SvGrid, type GridColumns } from '@svgrid/grid'

  type Person = {
    id: number
    name: string
    department: string
    city: string
    age: number
    salary: number
  }

  const people: Person[] = [
    { id: 1, name: 'Ada Lovelace',   department: 'Engineering', city: 'London',   age: 36, salary: 142000 },
    { id: 2, name: 'Grace Hopper',   department: 'Engineering', city: 'New York', age: 45, salary: 168000 },
    { id: 3, name: 'Linus Torvalds', department: 'Platform',    city: 'Portland', age: 54, salary: 155000 },
    { id: 4, name: 'Radia Perlman',  department: 'Networking',  city: 'Seattle',  age: 49, salary: 161000 },
    { id: 5, name: 'Barbara Liskov', department: 'Platform',    city: 'Boston',   age: 52, salary: 172000 },
  ]

  let rows = $state<Person[]>(people)
  const data = people

  const columns: GridColumns<Person> = [
    { field: 'name',       header: 'Name',       width: 200 },
    { field: 'department', header: 'Department', width: 150 },
    { field: 'city',       header: 'City',       width: 140 },
    { field: 'age',        header: 'Age',        width: 90 },
    { field: 'salary',     header: 'Salary',     width: 130, format: { type: 'currency', currency: 'USD' } },
  ]
</script>
const columns: GridColumns<Person> = [
  { field: 'firstName', header: 'First name' },
  { field: 'lastName',  header: 'Last name' },
  {
    id: 'compensation',
    header: 'Compensation',
    columns: [
      { field: 'salary', header: 'Salary',
        format: { type: 'currency', currency: 'USD' } },
      { field: 'bonus',  header: 'Bonus',
        format: { type: 'currency', currency: 'USD' } },
    ],
  },
]

Rendered as:

|              | Compensation         |
| First | Last | Salary | Bonus       |

How it works

Nested groups

Groups can nest arbitrarily. The grid emits one header row per depth level:

{
  header: 'Q1',
  columns: [
    { header: 'Jan', field: 'jan' },
    { header: 'Feb', field: 'feb' },
    { header: 'Mar', field: 'mar' },
  ],
},
{
  header: 'Q2',
  columns: [/* … */],
},

Collapsible groups (columnGroupShow)

Give a group a collapse toggle by tagging its child columns:

Setting it on any direct child adds a caret to the group header. Use openByDefault on the group to start expanded (default is collapsed).

{
  id: 'q1', header: 'Q1', openByDefault: true,
  columns: [
    { field: 'q1Total', header: 'Total' },                    // always visible
    { field: 'jan', header: 'Jan', columnGroupShow: 'open' },  // only when expanded
    { field: 'feb', header: 'Feb', columnGroupShow: 'open' },
    { field: 'mar', header: 'Mar', columnGroupShow: 'open' },
  ],
}

Collapsing/expanding hides or shows the tagged leaves and the group header's colSpan recomputes so the multi-level header stays aligned.

Open the live example: Collapsible column groups (Columns)

Group with a custom header

The same header: (ctx) => renderSnippet(...) pattern from custom header components works for group headers. The ctx.header.colSpan value will be the rendered span.

Gotchas

Try it

A group is a column with columns instead of a field. Nest as deep as you need; the header row count follows the deepest branch.

<script lang="ts">
  const grouped: GridColumns<Person> = [
    { field: 'name', header: 'Name', width: 200 },
    {
      header: 'Employment',
      columns: [
        { field: 'department', header: 'Department', width: 150 },
        { field: 'salary', header: 'Salary', width: 130, format: { type: 'currency', currency: 'USD' } },
      ],
    },
    {
      header: 'Personal',
      columns: [
        { field: 'city', header: 'City', width: 140 },
        { field: 'age', header: 'Age', width: 90 },
      ],
    },
  ]
</script>

<SvGrid data={people} columns={grouped} />

See also

Live examples

  • Pivot - Table + Designer - Drag-and-drop Pivot Designer with Filters / Rows / Columns / Values zones, multi-level column headers, subtotal + grand-total rows, row-header sort menu.
  • Collapsible column groups - Each quarter is a column group with a header caret. The Total is always shown; month columns tagged columnGroupShow:"open" appear only when the group is expanded. openByDefault controls the initial state.

Related articles