You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Data Grid has no first-class way to align a column. Today consumers hand-roll it with class names:
{accessorKey: "amount",meta: {cellClassName: "text-end",// Reaches into the component's internal DOM: the header content wrapper// is a private flex div, and headerClassName only lands on the <th>.headerClassName: "text-end [&>div]:w-full [&>div]:justify-end",},}
Three problems with this:
The header content layout has no public handle.meta.headerClassName is applied to the <th>, but the header content is wrapped in an internal flex div (-ms-2 flex h-full items-center justify-between gap-1.5 in data-grid-column-header.tsx). Positioning the trigger inside the cell forces consumers to select internal DOM with [&>div] variants.
It couples consumer styles to internal structure. The [&>div] idiom recently caused a real bug: on resizable grids the same selector matches the column resize handle (also a direct div child of the <th>), and the compiled .\[\&\>div\]\:w-full>div (0,1,1) out-specifies the handle's .w-5 (0,1,0) — stretching the absolute handle across the whole header cell and swallowing every click. See fix(data-grid): prevent resize handle from covering header menu on end-aligned columns #120.
The recipe must be repeated per column (start / center / end each need their own class string), and skeletons need separate handling again.
Proposal
Add a semantic alignment field to the column meta contract, e.g.:
the header content wrapper gets the matching w-full + justify-* internally (no consumer selector needed);
meta.skeleton alignment follows the same edge.
Open questions
One knob or two? A single align covers the common case (numeric columns right-align both header and cell). Separate headerAlign / cellAlign would allow e.g. a start-aligned header over end-aligned cells. Which is the right surface?
Interaction with existing headerClassName / cellClassName. Keep both as an escape hatch; explicit class names should still win over align-generated ones (or the contract should state the merge order).
Naming.align on meta vs. a top-level column field — meta seems right since TanStack keeps presentation data there, but worth confirming.
Scope. Both base and radix registries, docs, and an example (the c-* examples probably already carry the [&>div] idiom and could be migrated).
Problem
Data Grid has no first-class way to align a column. Today consumers hand-roll it with class names:
Three problems with this:
meta.headerClassNameis applied to the<th>, but the header content is wrapped in an internal flex div (-ms-2 flex h-full items-center justify-between gap-1.5indata-grid-column-header.tsx). Positioning the trigger inside the cell forces consumers to select internal DOM with[&>div]variants.[&>div]idiom recently caused a real bug: on resizable grids the same selector matches the column resize handle (also a directdivchild of the<th>), and the compiled.\[\&\>div\]\:w-full>div(0,1,1) out-specifies the handle's.w-5(0,1,0) — stretching the absolute handle across the whole header cell and swallowing every click. See fix(data-grid): prevent resize handle from covering header menu on end-aligned columns #120.Proposal
Add a semantic alignment field to the column meta contract, e.g.:
The component then owns the mapping:
<td>/<th>get the matchingtext-*class;w-full+justify-*internally (no consumer selector needed);meta.skeletonalignment follows the same edge.Open questions
aligncovers the common case (numeric columns right-align both header and cell). SeparateheaderAlign/cellAlignwould allow e.g. a start-aligned header over end-aligned cells. Which is the right surface?headerClassName/cellClassName. Keep both as an escape hatch; explicit class names should still win overalign-generated ones (or the contract should state the merge order).alignon meta vs. a top-level column field — meta seems right since TanStack keeps presentation data there, but worth confirming.baseandradixregistries, docs, and an example (the c-* examples probably already carry the[&>div]idiom and could be migrated).References
registry-reui/bases/{base,radix}/reui/data-grid/data-grid-table.tsx—meta.headerClassName/meta.cellClassNamemerge sitesregistry-reui/bases/{base,radix}/reui/data-grid/data-grid-column-header.tsx— internal header content wrapper