Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions .changeset/data-table-columns-and-row-nav.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@tailor-platform/app-shell": minor
---

DataTable: sticky/pinned columns, user column settings, and accessible row-click navigation

- **Pinned columns** — add `pin: "left" | "right"` to a `Column` (requires `width`) to freeze it during horizontal scroll. The selection column auto-pins left and the row-actions column auto-pins right, and a subtle freeze shadow appears at the frozen edge once content is scrolled under it.
- **`DataTable.ColumnSettings`** — a "Columns" toolbar popover to show/hide columns, reorder them (drag), and change pinning by dragging a column between the Fixed left / Scrollable / Fixed right zones.
- **Persisted column layout** — pass a stable `tableId` to `useDataTable` to persist each user's column visibility, order, and pinning to `localStorage` (per-user preference; not stored in the URL). Omit for in-memory-only layout.
- **`rowHref`** — accessible whole-row navigation. The primary cell renders as a real `<Link>` (keyboard/screen-reader reachable, cmd/middle-click opens a new tab) while the whole row stays clickable. Prefer this over a per-row "View" button; keep `onClickRow` for non-navigation side effects. Optional `primaryColumnId` chooses which cell carries the link.
- `Table.Root` now accepts an optional `containerRef` for its scroll container.
10 changes: 8 additions & 2 deletions catalogue/src/fundamental/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ Plus `badgeVariants` CVA for custom-styled siblings.

**Import:** compound namespace + helpers from `'@tailor-platform/app-shell'`, e.g. `DataTable`, `useDataTable`, `useCollectionVariables`, `createColumnHelper`, and types such as `Column`, `UseDataTableReturn`.

**Purpose:** Production list screens over GraphQL **connections**. Owns toolbar filter chips (**`DataTable.Filters`** from column `filter` configs), header sort, **`DataTable.Pagination`** (cursor-first; First/Last when `total` is provided), loading skeleton/error row, **`onClickRow`**, **`rowActions`** (kebab column), **`onSelectionChange`** (checkbox column).
**Purpose:** Production list screens over GraphQL **connections**. Owns toolbar filter chips (**`DataTable.Filters`** from column `filter` configs), header sort, **`DataTable.Pagination`** (cursor-first; First/Last when `total` is provided), loading skeleton/error row, **`rowHref`** (accessible whole-row navigation — preferred) / **`onClickRow`** (non-navigation side effects), **`rowActions`** (kebab column), **`onSelectionChange`** (checkbox column), **column pinning** (`pin: "left" | "right"`) and **`DataTable.ColumnSettings`** (user show/hide + reorder + pin, persisted per-user via **`tableId`**).

**Primitives:** Builds on low-level **`Table`**; do not reinvent pagination/filters manually unless the dataset is trivial.

Expand All @@ -404,13 +404,15 @@ const table = useDataTable({
data: fetching ? undefined : mappedFromQuery,
loading: fetching,
control,
onClickRow: (row) => navigate(detailHref(row)),
tableId: "purchase-orders", // persist user column layout to localStorage
rowHref: (row) => detailHref(row), // whole-row nav; primary cell becomes a <Link>
// onSelectionChange, rowActions, sort: …
});

<DataTable.Root value={table}>
<DataTable.Toolbar>
<DataTable.Filters />
<DataTable.ColumnSettings />
</DataTable.Toolbar>
<DataTable.Table />
<DataTable.Footer>
Expand All @@ -419,6 +421,10 @@ const table = useDataTable({
</DataTable.Root>;
```

**Row navigation:** prefer **`rowHref`** over `onClickRow` for going to a detail page — it renders the primary cell as a real `<Link>` (keyboard/SR reachable, cmd/middle-click opens a new tab) while keeping the whole row clickable. Use `onClickRow` only for non-navigation side effects. Never add a per-row "View" / "Open" / "→" button.

**Column pinning & settings:** set `pin: "left" | "right"` on a `Column` (it must have a `width`) to freeze it during horizontal scroll — selection auto-pins left, row-actions auto-pins right. Drop **`DataTable.ColumnSettings`** in the toolbar to let users show/hide, reorder, and re-pin columns; pass a stable **`tableId`** to persist their layout to `localStorage` (a per-user preference — intentionally not in the URL like filters/sort).

**Column alignment:** each `Column` accepts **`align`** (`"left" | "right"`) applied to both header and body cell. Numeric `type` columns (`"number"`, `"money"`) default to `"right"` automatically so digits align on the decimal place — pass `align="left"` to opt out; everything else defaults to `"left"`.

**Metadata path:** Prefer `createColumnHelper` + `inferColumns(tableMetadata.order)` (`@tailor-platform/app-shell-sdk-plugin` codegen) when available so enum/datetime/string filters bind to the right editors.
Expand Down
3 changes: 2 additions & 1 deletion catalogue/src/pattern/list/dense-scan/PATTERN.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ Omit `fill` on pages that should flow and scroll naturally (forms, dashboards, a
- Handle every state: `DataTable` renders the loading skeleton and error row; always provide a **labelled empty state** (what the list is + how to add the first record) rather than a bare empty table
- Status Badge colors must use design system tokens (variant prop): the **primary** status column uses **filled** semantic variants; **secondary** status columns (delivery, billing) use **`outline-*`** (see `design-system.md` → Composition & emphasis rules)
- Bulk actions toolbar appears only when ≥1 row is selected
- Whole row is clickable via `onClickRow`; no per-row "View" / "Open" buttons
- Whole row navigates via `rowHref` (renders the primary cell as an accessible `<Link>`); use `onClickRow` only for non-navigation side effects. No per-row "View" / "Open" buttons
- Per-row `Menu` (overflow `…`) is reserved for non-navigation actions (Archive, Duplicate, Delete)
- Wide lists: pin key columns with `pin: "left" | "right"`, and offer `DataTable.ColumnSettings` (show/hide + reorder + pin) with a `tableId` so each user's layout persists

## Anti-patterns

Expand Down
Loading