Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
7c29701
docs(data-table): add library comparison (VTable/S2/TanStack)
depthark Jul 25, 2026
23437eb
build(ui-kit): add TanStack Table, virtual and dnd-kit deps
depthark Jul 25, 2026
29da94a
docs(ui-kit): add data-table-usage skill + changelog entry
depthark Jul 25, 2026
8eacecb
feat(ui-kit): add DataTable organism (TanStack, headless)
depthark Jul 25, 2026
6fb522d
test(ui-kit): add DataTable stories with interaction tests
depthark Jul 25, 2026
72d28f8
fix(ui-kit): address DataTable review (Greptile P1)
depthark Jul 25, 2026
6ee7bc1
docs(data-table): address review nits (CodeRabbit)
depthark Jul 25, 2026
9b883f1
fix(ui-kit): second review round (Greptile/CodeRabbit)
depthark Jul 25, 2026
7c3ba69
fix(ui-kit): preserve slotProps.row ref when not reordering
depthark Jul 25, 2026
c75f2c5
fix(ui-kit): type slotProps.row ref so the dts build passes
depthark Jul 25, 2026
f6fe01a
feat(ui-kit): type-driven filters/editors, inline edit mode, size pro…
depthark Jul 25, 2026
5645395
test(ui-kit): stories for typed filters, custom filter, inline edit a…
depthark Jul 25, 2026
7de9cf7
fix(ui-kit): review round on typed fields and actions column
depthark Jul 25, 2026
583ba77
feat(ui-kit): constrainable row selection (mode, cap, custom predicate)
depthark Jul 25, 2026
e4bb06b
feat(ui-kit): per-row action permissions; fix sticky header/frozen st…
depthark Jul 25, 2026
025ff09
fix(ui-kit): visual fixes found by browsing every DataTable story
depthark Jul 25, 2026
19c70e5
feat(ui-kit): drag affordances and loading skeletons
depthark Jul 25, 2026
fd46663
feat(ui-kit): standalone striped boolean; drop click affordance while…
depthark Jul 25, 2026
2ed9e94
feat(ui-kit): accessibility for DataTable
depthark Jul 25, 2026
272a89f
fix(ui-kit): address DataTable a11y review findings
depthark Jul 25, 2026
bbdf992
fix(ui-kit): correctness review findings (P0/P1)
depthark Jul 25, 2026
80b1433
fix(ui-kit): filter-row pinning and edit-lock bypass
depthark Jul 25, 2026
a2faa56
docs(ui-kit): correct bundled skill count in agent-plugin README
depthark Jul 25, 2026
5b862f3
fix(ui-kit): opaque header cells so frozen columns don't bleed through
depthark Jul 25, 2026
683d830
feat(ui-kit): compact filter row, Button row actions, drop quick actions
depthark Jul 25, 2026
4371a63
feat(ui-kit): expander in actions cell, free-form detail row, right-a…
depthark Jul 25, 2026
1a67e14
fix(ui-kit): compact filter condition menu, translatable operator labels
depthark Jul 25, 2026
d082ca5
docs(ui-kit): record size-scale inconsistencies as follow-up tasks
depthark Jul 25, 2026
a42c4fa
fix(ui): allow sorting the demo Status column
depthark Jul 25, 2026
5e0f3c4
feat(ui): column widths, alignment, wrapper radius, hover-only drag h…
depthark Jul 25, 2026
16a9eda
feat(ui): data-align styling in Table, rework InlineEdit story
depthark Jul 25, 2026
894e120
fix(ui): address CodeRabbit review on DataTable
depthark Jul 25, 2026
dcc8ba4
fix(ui): mirror numeric column widths into TanStack's size model
depthark Jul 25, 2026
2c49fa5
ci(ui): gate Storybook play functions, fix what that exposed
depthark Jul 26, 2026
e710c3e
fix(ui): give the DataTable footer the header background
depthark Jul 30, 2026
43961ad
Revert: drop the Storybook interaction-test CI infrastructure
depthark Jul 30, 2026
528632c
feat(ui): split the DataTable footer — range left, pager and page siz…
depthark Jul 30, 2026
746d460
feat(ui): toolbar actions, SearchForm-based search, wrapper border
depthark Jul 30, 2026
9035fd9
fix(ui): make the toolbar search fill the row and join its search button
depthark Jul 30, 2026
05e3279
feat(ui): icon-only column settings trigger, keep its checkbox list open
depthark Jul 30, 2026
9bbc9ef
fix(ui): make the column-settings trigger clickable again
depthark Jul 30, 2026
24afa24
fix(ui): resolve outstanding CodeRabbit findings on DataTable
depthark Jul 30, 2026
55aae8f
docs: translate the DataTable library comparison to English
depthark Jul 30, 2026
75e4ce0
build(ui-kit): migrate DataTable to TanStack Table v9
depthark Aug 20, 2026
35def96
fix(ui): resolve the open CodeRabbit threads on DataTable
depthark Aug 20, 2026
5e9979c
fix(ui): correct the v9 migration against the TanStack migration guide
depthark Aug 20, 2026
0eef9b7
fix(ui): remove unreachable lock reporting, guard blank numeric cells
depthark Aug 20, 2026
39db663
style(ui): use type aliases for the Table prop definitions
depthark Aug 20, 2026
0794761
fix(ui): drop the now-dead blocked ref, align between with matchNumber
depthark Aug 20, 2026
c505c04
fix(ui): default filterFn so the typed filter row actually filters
depthark Aug 20, 2026
379c72c
fix(ui): stack grouped sticky headers, scope the rowClick block report
depthark Aug 20, 2026
cdc4b80
fix(ui): render the toolbar for actions alone, stop swallowing row on…
depthark Aug 20, 2026
ffd327b
fix(ui): empty date/time filters no longer hide blank cells
depthark Aug 20, 2026
40db5ea
fix(ui): stack the sticky actions cell above frozen body columns
depthark Aug 20, 2026
e6e1d55
fix(ui): give meta.type: "custom" a dispatch case in typedFilterMatch
depthark Aug 20, 2026
58fd4b2
fix(ui): honour deprecated filterVariant, stop silently truncating vi…
depthark Aug 20, 2026
193ee48
fix(ui): restore sticky headers, stop the filter select reflowing the…
depthark Aug 21, 2026
05b18f9
fix(ui): widen the filter select's stable-width buffer
depthark Aug 21, 2026
b18bd1e
feat(ui): striped rows drop their border, add tintNestedRows
depthark Aug 21, 2026
59fbd7e
fix(ui): fire the virtualization warning once, tokenize the nested-ro…
depthark Aug 21, 2026
c0ab9ea
fix(ui): re-warn on virtualization configs that turn invalid after mount
depthark Aug 21, 2026
66c1a1e
fix(ui): blank cells no longer pass numeric conditional filters, fix …
depthark Aug 22, 2026
c1fc479
fix(ui): stop swallowing infinite-scroll reach-end, fix inverted nume…
depthark Aug 22, 2026
b101499
fix(ui): numeric conditional-filter equals, cell-editor type, virtual…
depthark Aug 22, 2026
7599f9a
fix(ui): treat "int" columns as numeric in conditional filter, unify …
depthark Aug 22, 2026
27d5757
fix(ui): re-export filter/editor types, share between-range logic, fo…
depthark Aug 22, 2026
dd608c2
fix(ui): re-clamp maxSelectedRows on prop shrink, gate toolbar-overfl…
depthark Aug 22, 2026
92d3e17
fix(ui): fire onReady once, measure sticky header before paint, share…
depthark Aug 22, 2026
5d56803
fix(ui): render the numeric inline editor, label FieldSelect, auto-re…
depthark Aug 22, 2026
8423483
fix(ui): keep chosen filter operators, unbreak row+column reorder, re…
depthark Aug 22, 2026
13bd81b
fix(ui): stop infinite reach-end loop, fix date filters across timezones
depthark Aug 22, 2026
9f9c9b2
fix(ui): restore numeric arrow stepping, report column-reorder indice…
depthark Aug 22, 2026
9ac03c8
fix(ui): make sticky-actions stacking deterministic over end-pinned c…
depthark Aug 22, 2026
c60c1c9
fix(ui): render filter row, tree indent and skeleton in pinned column…
depthark Aug 22, 2026
8250f54
fix(ui): re-arm window-mode infinite scroll, stop paginationProps clo…
depthark Aug 23, 2026
9a21160
fix(ui): honour pageCount in the pager, restore leaf-column memoization
depthark Aug 23, 2026
4c9e30a
fix(ui): show row colour in frozen columns, actually memoize leaf col…
depthark Aug 23, 2026
3aebdaf
fix(ui): reset selection-limit latch, include blanks in numeric ≠, va…
depthark Aug 23, 2026
fa4b8ba
fix(ui): make plain TanStack filter values work, fix two broken story…
depthark Aug 23, 2026
9c36238
Merge branch 'master' into feat/data-table-tanstack
BleedingDev Aug 23, 2026
fca0144
fix(ui): unbreak conditional filters on non-operator column types
depthark Aug 23, 2026
4c982bf
fix(ui): coerce bare date/time and boolean filter values instead of n…
depthark Aug 23, 2026
8510791
fix(ui): seed the edit draft for controlled editingRowId, stop wideni…
depthark Aug 23, 2026
60d408d
fix(ui): stop undefined translations crashing the table, tag drags by…
depthark Aug 23, 2026
da435ec
fix(ui): stop frozen columns going see-through on striped and selecte…
depthark Aug 23, 2026
aeb2167
fix(ui): commit the current draft, unstick underfilled infinite scroll
depthark Aug 23, 2026
79dbca2
fix(ui): guard window-scroll reach-end, keep built-in columns leading
depthark Aug 23, 2026
2970cb1
Merge branch 'master' into feat/data-table-tanstack
BleedingDev Aug 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions docs/data-table/00-library-comparison.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# DataTable — library comparison and rationale

> Background for the decision on which library to build the new `DataTable` component in `libs/ui` on.
> Each library's documentation was fetched via **context7 MCP** (official sources) and mapped onto our requirement list.
> Analysis date: 2026-07-25.

## TL;DR

The hard requirement was: **headless, with open paths through props — able to shape the DOM and reach nested layers**, so the table fits our DS (Zag.js + Tailwind, DOM-first, `data-[...]` states, design tokens via CSS).

The whole comparison turns on **a single axis: canvas vs. DOM rendering.**

| Library | Rendering | Headless | Tailwind on cells | DS integration | Verdict |
|---|---|---|---|:--:|---|
| **TanStack Table** v8/v9 | **DOM** (you render it) | **yes, 100%** | **yes** | **1–2 / 5** | ✅ natural fit for the DS |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
| **VTable** (Bytedance) | **canvas** (VRender) | no | no | 5 / 5 | ⚠️ most features out of the box, but outside the DS |
| **AntV S2** (Alibaba/Ant) | **canvas** (AntV/G) | no | no | 5 / 5 | ❌ pivot/analytics, not a styleable grid |
| ali-react-table (Alibaba) | DOM | partially | yes | 4 / 5 | ❌ dead project, Chinese-only docs, no context7 coverage |
| _(baseline)_ antd Table | DOM | no (CSS-in-JS) | override wars | 3 / 5 | ⚠️ not headless |

> **The "DS integration" scale is integration cost/effort (1 = least, 5 = most), not library quality.** That is why TanStack scores `1–2 / 5` and wins, while the canvas libraries score `5 / 5` and lose.

**A clarification on "the Alibaba table":** what we had in mind (`ali-react-table`) is effectively unmaintained, documented only in Chinese, with zero context7 coverage. The genuinely live "Alibaba/Ant Group" table is **AntV S2** — but that is a canvas pivot/analytics table. So VTable (Bytedance) and S2 (Alibaba) are **both canvas** and hit the same problem.

## Why canvas is a problem for our DS

VTable and S2 both draw cells as **pixels on a single `<canvas>`**:

- **No per-cell DOM nodes** → no `className`, no `data-[validation=error]`, no CSS variables, no Tailwind on the table's content.
- Styling goes through a **parallel JS "theme" object** (`themeCfg`, VRender style objects) — we would have to **duplicate our entire token system** into a second language and maintain a bridge adapter.
- "Nested layers through props" does not really exist — you only get **overlay escape hatches** (absolutely positioned HTML/React above the canvas for editors, filter menus, popups). That does not scale to styling every cell.
- Bonus problems: accessibility (ARIA on elements) and debugging (S2 needs a dedicated "G devtools" plugin).

That is the philosophical opposite of a Zag.js + Tailwind DS, whose whole premise is "you own the DOM and the styling, we own the behaviour".

## Requirement matrix (native support)

Legend: ✅ native · 🟡 logic yes / you build the UI (or via a plugin) · ⚙️ only through custom or external code · ❌ missing

| # | Requirement | TanStack | VTable | AntV S2 |
|---|---|:--:|:--:|:--:|
| 1 | Column filters with conditions | 🟡 logic, UI DIY | ✅ FilterPlugin (byCondition) | 🟡 `onFilter` pipeline |
| 2 | Header filter template | ⚙️ build it in `<th>` | ✅ `headerCustomLayout` | ✅ `custom-header`/`colCell` |
| 3 | Fulltext search | ✅ `globalFilter` | 🟡 search plugin | ⚙️ pre-filter the data |
| 4 | Sorting | ✅ `getSortedRowModel` | ✅ `sort` + comparator | ✅ `sortParams` |
| 5 | Empty data template | ⚙️ DIY | ✅ empty-tip | ✅ `placeholder` |
| 6 | Row actions | ⚙️ display column | ✅ `cellType:'button'`/icon | ⚙️ custom/overlay |
| 7 | Freeze columns L/R | 🟡 `columnPinning` (+CSS) | ✅ `frozenColCount`/`rightFrozenColCount` | ✅ `frozen{...}` |
| 8 | Sticky header | ⚙️ CSS `sticky` | ✅ native | ✅ `stickyHeader` |
| 9 | Striped rows | ⚙️ CSS `nth-child` | 🟡 via theme | 🟡 via theme |
| 10 | Infinite scroll / virtual | ⚙️ +`@tanstack/react-virtual` | ✅ strong native | ✅ strong native |
| 11 | ColSpan / RowSpan | ❌ header groups only | ✅ `customMergeCell` | ✅ `mergedCell` |
| 12 | onRowClick | ⚙️ `onClick` on `<tr>` | ✅ `click_cell`→row | ✅ `ROW_CELL_CLICK` |
| 13 | Selectable rows (checkbox) | 🟡 `rowSelection` state | ✅ `cellType:'checkbox'` | 🟡 cell selection |
| 14 | Column reorder | 🟡 `columnOrder` (drag=dnd-kit) | ✅ `dragOrder` | 🟡 via API |
| 15 | Row reorder | ⚙️ dnd-kit + mutate data | ✅ `rowSeriesNumber.dragOrder` | ⚙️ custom |
| 16 | Show/hide columns | ✅ `columnVisibility` | 🟡 `updateColumns` | ✅ `fields.columns` |
| 17 | Row custom content template | ✅ `cell` + `flexRender` | ✅ `customLayout`/VRender | ✅ subclass `DataCell` |
| 18 | Tree structure | ✅ `getExpandedRowModel` | ✅ strong `tree:true` | ✅ strong tree mode |
| 19 | Quick actions | ⚙️ display column | ✅ button/icon | ⚙️ interaction API |
| 20 | Inline row edit | ❌ DIY (`meta.updateData`) | ✅ `vtable-editors` | 🟡 editable-sheet/custom |
| 21 | Pagination (count, page size) | ✅ `getPaginationRowModel` | ✅ `pagination` | ✅ `pagination` |

**How to read this:** VTable and S2 win on ✅ count — they are "batteries-included". TanStack has more 🟡/⚙️ because it **deliberately ships no UI** — it gives you the state machine and you build the markup from your own atoms (which is an advantage for a DS, not a drawback).

## Integration effort for our DS (Zag.js + Tailwind)

- **TanStack — 1–2/5:** the same philosophy as Zag.js (logic only, zero markup/CSS). Filter inputs, checkboxes, pager and sort icons are rendered through our existing Zag atoms → the table inherits our tokens and the `data-[validation]` pattern for free. The cost: you build every piece of UI yourself, and add virtualization (`@tanstack/react-virtual`), drag (`dnd-kit`) and inline edit by hand; **rowSpan/colSpan on data cells is genuinely missing**.
- **VTable — 5/5:** canvas cannot be styled with Tailwind or wired to tokens. You get many features out of the box but lose the whole DS — cells are not members of the headless family, just an isolated widget behind a token→theme adapter. It only makes sense at canvas-scale performance (100k+ cells, pivot).
- **AntV S2 — 5/5:** the same, plus it is over-engineered for pivot analytics, and the English docs are a thin subset.
- **ali-react-table — 4/5 with high uncertainty:** DOM-based and virtualized, but a dead project with Chinese-only docs and no context7 coverage.

## Decision (final)

**Chosen: `@tanstack/react-table` v9.** For a **headless, Tailwind-styleable, DOM-accessible** grid inside a Zag.js DS it is architecturally the only clean fit. VTable (Bytedance) and AntV S2 (Alibaba) are **canvas** → they cannot use our stack (`--color-table-*` tokens, `tailwind-variants` slots, `data-[…]` states, Zag atoms), so they were ruled out. Bonus: `@tanstack/react-table` was already in the repo (`apps/medusa-be`), so no new third-party platform. The organism was first built against v8 and migrated to v9 before merge; v9 moves feature registration and the row models onto a module-scope `tableFeatures()` set and renames column pinning from `left`/`right` to `start`/`end`.

**Why not VTable/S2 despite more out-of-the-box features:** their canvas rendering would mean a parallel JS theme system (a duplicate of our token set), no per-cell DOM access through props, and losing accessibility and DOM-level testability. They only make sense as an **isolated canvas analytics widget** outside the DS (canvas-scale 100k+ cells, pivot).

**How we covered TanStack's weak spots:**
- colSpan/rowSpan on data cells → a custom `getCellSpan` prop (TanStack has none).
- virtualization / infinite scroll → `@tanstack/react-virtual` (windowing that preserves native table alignment) + `onReachEnd`.
- column & row reorder → `@dnd-kit`.
- inline edit → `meta.updateData` → `onCellEditCommit`.

**Implementation:** the `DataTable` organism in `libs/ui/src/organisms/data-table.tsx`, rendering through the existing presentational `Table` organism (so it inherits the `--color-table-*` tokens). It covers all 21 requirements, every feature exposes a callback, with Storybook stories carrying `play` interaction tests and the `data-table-usage` usage skill. The MVP is styled with existing and semantic tokens; component-level `--color-data-table-*` tokens and the Figma export follow once the MVP look is signed off.
4 changes: 2 additions & 2 deletions libs/ui/agent-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ no spec-driven workflow.
| Type | Count | Purpose |
| --- | --- | --- |
| Workflow skills | 8 | `$ui-*` entry points: scaffold, tokens, stories, theming, Figma sync, validation, release, usage routing |
| Bundled deep skills | 58 | Synced 1:1 from `libs/ui/skills/`: per-component `*-usage` guides, `component-authoring`, `tailwind-token-authoring`, `storybook-authoring`, `zag-compound-components`, … |
| Bundled deep skills | 60 | Synced 1:1 from `libs/ui/skills/`: per-component `*-usage` guides, `component-authoring`, `tailwind-token-authoring`, `storybook-authoring`, `zag-compound-components`, … |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
| Subagents (Codex TOML) | 6 | design-system expert, component-dev orchestrator, token/story/figma specialists, QA gate |
| Hooks | 2 | Real git `pre-push` gate (auto-installed in the ui-kit source repo only) + a `--no-verify` guard |
| MCP servers | 3 | context7 (docs), figma (design context + Code Connect), chrome-devtools (browser) |
Expand Down Expand Up @@ -171,7 +171,7 @@ techsio-ui-kit-ai/
├── AGENTS.md # routing table
├── .mcp.json # context7, figma, chrome-devtools
├── agents/*.toml # 6 Codex subagents
├── skills/ # 8 authored workflow skills + 58 bundled deep skills
├── skills/ # 8 authored workflow skills + 60 bundled deep skills
├── hooks/
│ ├── hooks.json # SessionStart installer + --no-verify guard
│ └── pre-push # the real gate (git hands it the exact refs/SHAs)
Expand Down
Loading
Loading