Skip to content

DataGrid: collapsible plugin (row truncation + expand toggles)#58

Open
bemky wants to merge 5 commits into
mainfrom
feature/data-grid-collapsible
Open

DataGrid: collapsible plugin (row truncation + expand toggles)#58
bemky wants to merge 5 commits into
mainfrom
feature/data-grid-collapsible

Conversation

@bemky

@bemky bemky commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Summary

Adds an opt-in collapsible plugin for the virtualized DataGrid (and subclasses like DataSpreadsheet) — the windowed counterpart of the Table collapsible plugin, with the same semantics:

  • collapseTo (any valid CSS size, default auto) sets a height budget for rows via max-height: var(--expandTo, var(--collapseTo)).
  • Rows whose cell content overflows are truncated and flagged with a collapsed attribute; each overflowing cell gets a gradient chevron toggle (same affordance as Table's).
  • Clicking expand sizes the row to that cell's full content by setting --expandTo on the row element; the collapse toggle reverses it.

Like the sibling resizable/reorderable DataGrid plugins, it is not auto-included — consumers opt in with DataGrid.include(collapsible) / DataSpreadsheet.include(collapsible).

Virtualization integration

The tricky part is that DataGrid pools/recycles row and cell elements and drives windowing off measured heights. The plugin leans on the existing pipeline instead of adding geometry code:

  • Clamping is pure CSS, so the grid's normal measure pass records the clamped height; expanding (--expandTo) resizes the element, which the grid's own row ResizeObserver already turns into measure()reflow() — offsets, the mounted window, and the body scroll extent update for free.
  • Expanded state lives on the persistent DataGridRow controller (row.expandedColumns, a Set of columns), never on pooled elements. The live cell is re-resolved on every pass via row.cellOf(column), and measured heights already travel with controllers — so an expanded row scrolled out of the window keeps its height and restores its expansion (and toggles) when it scrolls back in, and expansion survives sortRows/splices.
  • A plugin ResizeObserver watches mounted row elements (observe on mount, unobserve when pooled — re-observation gives each mount a free initial check). The check (checkRowCollapse) is idempotent: it always rebuilds toggles/attributes from controller state, so it can run on every resize (content rendering in, column resize rewrapping text, --expandTo changing).
  • Pooled elements are scrubbed of collapsed / collapse-toggle attributes on acquire, since unmount() only clears style/class.
  • Toggles for frozen columns get position: sticky + the cell's left; toggle pointerdown/mousedown are stopped so clicking one doesn't start a DataSpreadsheet selection.

Verified

Drove the data-spreadsheet demo (872 rows, collapseTo: '60px', multi-line Awards column) headlessly: truncation + toggles on load; expand grows the row 60→192px with the body scroll height growing by exactly the delta; scroll-away-and-back restores expansion on the recycled element; collapse reverts; column resize re-checks truncation; sortRows keeps expanded heights with their rows; toggle clicks don't trigger selection; no console/ResizeObserver errors.

🤖 Generated with Claude Code

bemky and others added 2 commits June 8, 2026 09:44
Add an opt-in collapsible plugin for the virtualized DataGrid, modeled on the
Table collapsible plugin but adapted to virtualization. Rows are grouped by a
key or key function; each group gets a full-width header row that toggles its
members open/closed.

Virtualization integration: the group structure is the source of truth, and the
currently-visible entries (always-visible headers + expanded members) are
projected onto grid.rows. The existing rowGeometry/updateWindow/scrollbar
pipeline consumes grid.rows unchanged, so a collapsed group contributes only its
header's height to the total extent. Toggling re-projects, repoints
rowGeometry.elements at the new array, and calls updateWindow().

No DataGrid core changes; everything is done via the same lifecycle/hook points
the sibling resizable/reorderable plugins use.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The first cut implemented group-by row collapsing; the intended feature
is the DataGrid counterpart of the Table collapsible plugin: collapseTo
sets a height budget for rows, overflowing cell content is truncated
behind a per-cell toggle, and expanding sizes the row to the cell's
full content via --expandTo. Expanded state lives on the persistent
DataGridRow controller (elements are pooled), and height changes flow
through the grid's existing measure/reflow pipeline so windowing and
the scroll extent stay correct.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bemky bemky changed the title DataGrid: collapsible plugin (row grouping + collapse) DataGrid: collapsible plugin (row truncation + expand toggles) Jun 12, 2026
bemky and others added 3 commits June 12, 2026 14:50
A cell's border-bottom sits at the cell's box bottom, which no longer
coincides with the visible row edge once collapsible clamps and clips
rows. An inset box-shadow on the row element paints at the row's used
box, so the line survives truncation/expansion with no layout impact.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
With the clamp on the row, the row's overflow clip sat exactly on the
cells' bottom edge and sheared off per-cell decorations there (the
demo's border-bottom grid lines). Cells already clip their own content
(overflow: hidden in core styles), and the row's track follows the
tallest clamped cell — so clamping only the cells yields the same
truncation while keeping the visible row edge inside each cell's box.
Reverts the demo's row-shadow workaround in favor of plain cell borders.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cells have a definite grid-column but an auto grid-row, so a prepended
overlay child (e.g. the collapsible plugin's toggle, which occupies
row 1 at its column) makes auto-placement bump the colliding cell to
row 2. Pinning cells to row 1 keeps overlays and cells coexisting in
the single row track.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant