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.

A live, editable Svelte 5 data grid example from the SvGrid gallery (Columns). See the SvGrid documentation for the full API.

About this example

Collapsible column groups in the Svelte 5 data grid. Each quarter is a column group with a caret in its header: the quarter Total is always visible and the month columns are tagged columnGroupShow: 'open' so they appear only when the group is expanded. Groups start collapsed, and openByDefault on the first quarter opens it initially.

Each quarter is a column GROUP with a collapse toggle in its header. The quarter Total is always visible; the month columns are tagged columnGroupShow: 'open', so they appear only when the group is expanded. Groups start collapsed by default - click a quarter header caret to reveal its months. Q1 starts open via openByDefault.

Imports, features and API used

Imports: @svgrid/grid

Table features registered: rowSortingFeature

Columns: region (Region)

Frequently asked questions

How do I make a column group collapsible?

Define the group with an id and a columns array, and tag the child columns that should hide when collapsed with columnGroupShow: 'open'. The header shows a caret automatically.

How do I keep one column visible in both states?

Leave columnGroupShow off that column. The quarter Total here has no tag, so it shows whether the group is open or closed.

How do I choose the initial state?

Set openByDefault: true on the group. Groups without it start collapsed.

Related documentation

Related articles

Source code (183-collapsible-column-groups.svelte)

<!-- Documented in: docs/help/columns/column-groups.md -->
<script lang="ts">
  /**
   * 183. Collapsible column groups (columnGroupShow)
   * ------------------------------------------------
   * Each quarter is a column GROUP with a collapse toggle in its header. The
   * quarter Total is always visible; the month columns are tagged
   * `columnGroupShow: 'open'`, so they appear only when the group is expanded.
   * Groups start collapsed by default - click a quarter header caret to
   * reveal its months. Q1 starts open via `openByDefault`.
   */
  import { SvGrid, tableFeatures, rowSortingFeature, type ColumnDef,
    type GridColumns } from '@svgrid/grid'

  type Row = { region: string } & Record<string, number | string>

  const QUARTERS = [
    { gid: 'g1', label: 'Q1', months: ['Jan', 'Feb', 'Mar'], total: 'q1', open: true },
    { gid: 'g2', label: 'Q2', months: ['Apr', 'May', 'Jun'], total: 'q2', open: false },
    { gid: 'g3', label: 'Q3', months: ['Jul', 'Aug', 'Sep'], total: 'q3', open: false },
    { gid: 'g4', label: 'Q4', months: ['Oct', 'Nov', 'Dec'], total: 'q4', open: false },
  ]

  const regions = ['North', 'South', 'EMEA', 'APAC', 'LATAM']
  const rows: Row[] = regions.map((region, ri) => {
    const r: Row = { region }
    QUARTERS.forEach((q, qi) => {
      let sum = 0
      q.months.forEach((m, mi) => {
        const v = 20_000 + ((ri * 7 + qi * 5 + mi * 11) % 40) * 1000
        r[m] = v
        sum += v
      })
      r[q.total] = sum
    })
    return r
  })

  const features = tableFeatures({ rowSortingFeature })
  const money = { type: 'currency', currency: 'USD', options: { maximumFractionDigits: 0 } } as const

  const columns: GridColumns<Row> = [
    { field: 'region', header: 'Region', width: 130 },
    ...QUARTERS.map(
      (q): ColumnDef<typeof features, Row> => ({
        id: q.gid,
        header: q.label,
        openByDefault: q.open,
        columns: [
          // Always-visible quarter total.
          { field: q.total, header: 'Total', width: 120, align: 'right', cellDataType: 'number', format: money },
          // Month breakdown - only while the group is expanded.
          ...q.months.map(
            (m): ColumnDef<typeof features, Row> => ({
              field: m,
              header: m,
              width: 100,
              align: 'right',
              cellDataType: 'number',
              format: money,
              columnGroupShow: 'open',
            }),
          ),
        ],
      }),
    ),
  ]
</script>

<section class="flex flex-col flex-1 min-h-0 gap-3">
  <p class="text-sm shrink-0" style="color: var(--sg-fg);">
    Each quarter is a <strong>collapsible column group</strong>. The
    <strong>Total</strong> is always shown; the months carry
    <code>columnGroupShow: 'open'</code> so they appear only when the group is
    expanded. Click a quarter's <strong>caret</strong> to expand/collapse - Q1
    starts open via <code>openByDefault</code>.
  </p>

  <div class="flex-1 min-h-0">
    <SvGrid responsive={true}
      columnResize
      data={rows}
      columns={columns}
      features={features}
      selectionMode="none"
      rowHeight={38}
      containerHeight="100%"
    />
  </div>
</section>

View this example on GitHub

More Columns examples

  • Column pinning + freezing - Wide 13-column grid. Pin Company left and Price right via the column menu; the middle scrolls under sticky edges.
  • Columns hierarchy + manager - Side-panel tree of grouped columns: drag leaves to reorder, click a chevron to collapse a group into one summary column, toggle visibility per leaf or whole group.
  • Column layout API - setColumnWidth + setColumnPinning + getColumnWidths + getColumnPinning. Save the snapshot to localStorage, restore on reload, drive widths and pins from buttons.
  • Tool panel (Columns + Filters) - The docked enterprise sidebar, two tabs. Columns: toggle visibility, reorder up/down, group by a column. Filters: an operator + value control per column (numeric operators come free via cellDataType), kept in sync with the column menu. Enable with the toolPanel prop.
  • Column reorder - Set enableColumnReorder on <SvGrid> and every header becomes draggable, with a drop indicator. api.setColumnOrder / getColumnOrder + onColumnOrderChange event; persist to restore across reloads.