Row Expansion
A row opens to reveal a panel of your own markup underneath it. Two options shape it: expandMode decides whether one panel is open at a time or many, and canExpand decides which rows get a chevron at all.
expandMode — many at once, or one at a time
The same grid twice, one property apart. Open two rows in the left one and both stay open; do it in the right one and the first closes itself. Everything else about the two is identical.
expandMode: 'multi' — the default
expandMode: 'single' — an accordion
Two grids, one factory, one parameter. Everything that differs between them came out of a single line:
rowExpand: { expandMode: 'multi' | 'single', estimatedHeight: 96 }
'multi'— the default. Every panel you open stays open. Use it when a reader is comparing rows, because closing one to read another loses the comparison.'single'— opening a row closes the one that was open. An accordion: the grid never grows past one panel's worth of extra height, which is what you want when the panel is tall.
The panel is your markup. <ng-template #gcExpandRow> goes
inside <gridcraft> and receives an ExpandContext<T> whose
$implicit is the parent row — so let-row needs no name. A card, a chart,
a form, another component of yours: the grid only decides where it goes and how much height to
reserve for it.
The switch above changes animateRows, not the expansion. The panel
eases in over about a fifth of a second when a row opens; closing is always instant, because
holding a closing panel on screen keeps the rows below it from settling. Turn the switch off and
the panel simply appears. Readers who have asked their system for reduced motion never see the
animation either way — that is not something you have to detect.
canExpand — only the rows that have something to show
Half of these employees have notes on file and half do not. The ones that do carry a chevron; the ones that do not render as ordinary rows, with no toggle to press and nothing to open.
canExpand is a predicate over the row, and the grid asks it once per row:
rowExpand: { canExpand: row => row.notes.length > 0 }
Six of these twelve employees have notes on file. Those six carry a chevron; the other six carry nothing at all in that column — not a disabled toggle, no toggle. There is nothing to click, nothing to tab to, and nothing announced to a screen reader, which is the difference between "this row has no detail" and "this button does nothing".
Everything else about those rows is ordinary: they sort, they select, they take a cell template, and they line up with the rest. The predicate governs the toggle and nothing more.
Return true for a row whose detail you have not loaded yet — the panel is your
markup, so an empty state or a spinner inside it is a perfectly good answer, and a better one
than a row that cannot be opened because a request is still in flight.
What expanding a row does
config.rowExpand adds a toggle column and lets each row open a panel directly beneath
it. The panel takes real vertical space: the rows below move down, the scrollbar
grows, and the virtual scroller accounts for it — it is not an overlay floating over the grid.
What goes in the panel is <ng-template #gcExpandRow>, projected inside
<gridcraft>. Its context is ExpandContext<T> and
$implicit is the parent row, so let-row is all the binding you need.
estimatedHeight, and why it matters
The grid reserves rowExpand.estimatedHeight pixels the moment a row opens, then
measures what your panel actually rendered and corrects. A good estimate makes that correction
invisible; a bad one makes the rows below jump once. The default is 200, and both
examples here set 96, which is close to what their panels really are.
Content whose height is not known until it arrives — images, a lazily-loaded list — will always settle once. That is expected, and a minimum height on your own panel is the usual way to keep the correction small.
expandMode
'multi'(default) — panels accumulate. Opening one does not close another.'single'— opening one closes the other, accordion style.
canExpand
canExpand: (row) => boolean decides which rows get a toggle at all. A row that
answers false renders with no chevron — not a disabled one — and cannot be opened by
mouse or keyboard. Everything else about it is unchanged.
Motion
config.animateRows eases the panel in when a row opens; closing is always instant.
The same option governs rows revealed under a group or a tree node, so a grid has one motion
setting rather than one per feature, and it is skipped entirely for readers who have asked their
system for reduced motion.
Putting a whole nested grid in the panel — rowExpand.subGrid, with
its own columns, data source and isolated services per parent row — is part of the enterprise
package. The template above is the free way to put anything you like in a panel, including your
own components.
Row expansion options
| Property | Type | Default | Description |
|---|---|---|---|
| config.rowExpand | RowExpandConfig<T> | — | Turns on the expand toggle column. Panels take real vertical space in the scroll area rather than floating over it. |
| rowExpand.expandMode | 'multi' | 'single' | 'multi' | 'single' closes the open panel when another row opens — an accordion. |
| rowExpand.estimatedHeight | number | 200 | Pixels reserved before the panel is measured. The closer to the real height, the smaller the one-time correction. |
| rowExpand.canExpand | (row: T) => boolean | every row | Rows that answer false render with no chevron at all — not a disabled one — and cannot be opened by mouse or keyboard. |
| #gcExpandRow | ng-template (ExpandContext<T>) | — | The panel template, projected inside <gridcraft>. $implicit is the parent row, so let-row is enough. |
| config.animateRows | boolean | true | Eases the panel in on open; closing is always instant. Also covers rows revealed under a group or tree node, and is skipped under reduced-motion. |