Expansion
Detail panels that open under a row, lazily rendered, animated, and pinned to the viewport width so a wide table cannot scroll them away.
Basics
Loading example…
renderDetailPanel puts a full-width row under the row it belongs to, and an expand column with
a chevron appears automatically.
<DataTable
renderDetailPanel={({ row }) => <OrderLines orderId={row.id} />}
columns={columns}
data={orders}
/>
The panel is not rendered until it is opened, so a hundred collapsed rows cost nothing. Pass
detailPanelProps.keepMounted when the content is expensive to rebuild and should survive a
collapse.
Loading panel content
A panel usually needs data the table never fetched. useDetailPanelData loads it per row and
caches it by row id, so re-opening is instant:
function Panel({ row }) {
const { data, loading, error } = useDetailPanelData(row, () => api.lines(row.id));
if (loading) return <Spinner />;
if (error) return <ErrorText error={error} />;
return <OrderLines lines={data} />;
}
One at a time
expandMode: 'single' collapses the previous panel when another opens, like an accordion.
expandOnRowClick makes the whole row the toggle, with the same exclusion for buttons and links
that row selection uses. enableExpandAll puts an expand-all
toggle in the header.
Rows with children
Sub-rows use the same expansion state and the same toggle. That is a capability of its own; see Tree data.
Customization
The panel is sticky to the left at the container's width, so scrolling a wide table sideways does
not drag the panel out of view. detailPanelProps.fullWidth: false opts out and lets the panel
scroll with the columns.
The toggle is a slot, and positionExpandColumn moves
the column to the other end. The open/close animation is a CSS grid transition that
prefers-reduced-motion disables.
Limitations
- A row has one panel. Two kinds of detail (history and comments) belong in tabs inside the panel, not in two panels.
- A panel is not a cell. It is a separate row, so it takes no part in sorting, filtering, search or CSV export.
- The expanded state is keyed by row id, so it resets on refetch unless
getRowIdis stable andautoResetExpandedis off.
API
DataTableProps:enableExpanding,renderDetailPanel,detailPanelProps,expandMode,expandOnRowClick,enableExpandAll,getRowCanExpand,positionExpandColumn,paginateExpandedRows,autoResetExpanded,manualExpanding,onExpandedChange.TableInstance:setExpanded,resetExpanded,toggleAllRowsExpanded,getIsAllRowsExpanded,getExpandedRowModel.Row:toggleExpanded,getIsExpanded,getCanExpand.- Hooks:
useDetailPanelData.