| name | feedback-verify-data-grids | ||
|---|---|---|---|
| description | When porting a screen with a CSS Grid table (Day Book, Voucher Entry, Approvals, Ledger, Bank Recon, etc.), verify the computed `gridTemplateColumns` after first render. Don't trust screenshots — a column that collapsed to 0px renders no pixels and looks "fine" until you scroll into it. | ||
| metadata |
|
After porting any page that uses a custom CSS Grid for tabular content (Daybook.module.css .dbCols, VoucherEntry.module.css .gridCols, Approvals.module.css .qCols, etc.), the verification step is not "take a screenshot, eyeball it". It is:
- Open the page in chrome-devtools.
- Run
evaluate_scriptreadinggetComputedStyle(grid).gridTemplateColumnsand the per-cellgetBoundingClientRect().widthof each child. - Confirm every track is ≥ 50px wide. A track at 0px is a silent failure — it renders no pixels, so screenshots show nothing visibly wrong until you scroll horizontally or hover the column.
Why this is a separate feedback memory and not just a code rule:
Confirmed 2026-05-23 during the Day Book port. The grid declared minmax(0, 2.4fr) for the Particulars column. Other fixed columns totalled 796px in a 776px viewport. Grid honored the 0 floor and collapsed Particulars to 0px, then wrapped each word onto its own line for any cell content present. Screenshots looked superficially correct (the rest of the table rendered fine); only when the user pointed at the broken column did the issue become visible.
There are three distinct failure modes, all silent or easy to miss on screenshots:
- Collapse — a
minmax(0, *fr)track squeezed to0px(the Day Book bug). - Clip — the grid is wider than its container and the container is
overflow: hidden(or has no scroll wrapper), so the rightmost columns are cut off with no scrollbar (the Approvals / Ledger / Coa bug, 2026-05-23 — Stage/SLA/actions columns clipped at 208px). - Collision — the grid uses
gap: 0(or no column gap) and a right-aligned numeric cell (.num,text-align:right) is immediately followed by a left-aligned cell, so their text touches with zero whitespace. Confirmed 2026-05-24 on Coa: the "Closing Balance" header butted straight against "Status" → rendered "CLOSING BALANCESTATUS", and the• Activebadge jammed against the amount. Fix: give the grid a realcolumn-gap(row-gap: 0to keep density). Use ~0.8rem for normal tables, ≤0.5rem for dense Tally-style grids per [[feedback-dense-grids-stay-bespoke]]. KPI strips with per-cell padding +border-rightdividers are exempt. HTML<table>cells are exempt (padding separates them).
Remedy for clip when a wide grid sits beside an always-open side panel (<Sidebar>/<ThreePane>): a scroll wrapper stops the silent clip but still hides the decision-critical columns behind a scrollbar. The real fix is responsive column-dropping via a container query (established on Coa 2026-05-24, then swept across Ledger/Day Book/Outstanding/Aging/GST/CC Report/TB/Cash Flow):
container-type: inline-sizeon the scroll wrapper;@container (max-width: Npx)(N ≈ the grid's full natural min-width) redefinesgrid-template-columnsto the essential set,display:nones the dropped columns (stablecolXclasses on header and every data/section/total row), and setsmin-width: 0so the reduced grid stops forcing scroll.- Keep the primary name/identifier, all amount/balance/tax columns that are the screen's purpose, status, and row actions. Drop columns also shown in the side detail panel (codes, secondary dates, opening balances, intermediate aging buckets, CGST/SGST splits when total+IGST remain).
- Inherently-wide registers (10+ GST columns where dropping would gut the screen — Sales Register, GST output register, Purchase Invoice) keep legitimate horizontal scroll instead; just fix collision + ensure primary columns lead.
- Source-order gotcha (Ledger, 2026-05-24): a
@container { .bandRow { min-width: 0 } }reset MUST appear after the band row's basemin-width: 880pxrule in the stylesheet — otherwise the later base rule wins by source order and the band keeps pinning the scroll width even though the data rows shrank.
Protections now in place:
- Mandatory base wrapper
<DataGridScroll minWidth>(@mtp/ui, ADR-0013). EVERY data-grid / wide table MUST be wrapped in it. It owns BOTH halves of the no-clip invariant in one place: the outer div isoverflow-x: auto(never clips) and the inner div appliesmin-width, so the header, rows AND group bands inside all stretch to the same width and scroll together — no per-row/per-band min-width, no chance of forgettingoverflow. This is the structural fix that stops the clip class of bug recurring. - Lint (
mtp-web/.stylelintrc.json) rejectsminmax(0, *fr)mixed with a fixed-px track in the samegrid-template-columns(catches the collapse shape). Equal-fr (repeat(N, minmax(0,1fr))) and label patterns (120px 1fr) stay allowed. - This memory — manual chrome-devtools inspection catches the rest.
How to apply:
- Wrap every grid table in
<DataGridScroll minWidth={N}>(N = sum of fixed columns + a floor for flexible ones). Don't hand-rolloverflow-x: auto+ per-rowmin-width— that's exactly the manual discipline that got forgotten on screens built before the wrapper. - After first render in chrome-devtools run BOTH checks:
- collapse: every
gridTemplateColumnstrack ≥ ~50px. - clip: no element has
scrollWidth > clientWidthwhile itsoverflowXishidden/visible(excluding intentionaltext-overflow: ellipsistruncation). Snippet: scandocument.querySelectorAll('div,section,table')forel.scrollWidth > el.clientWidth+2 && getComputedStyle(el).overflowX==='hidden'.
- collapse: every
- Pre-wrapper screens already fixed inline (overflow-x:auto + min-width on rows/bands): Approvals, Ledger, Coa. Newer screens (TDS, GST, Outstanding, Aging, Sales Register, Bank Recon, Cost Centre, CC Report, Schedule III set) already had a scroll wrapper. Migrate the inline ones onto
<DataGridScroll>opportunistically. - For grouped tables (Day Book day-headers, Approvals bands, Ledger date-dividers) keep hand-rolling the CSS Grid rows —
<DataGridScroll>wraps them; a full column-config<DataGrid>(TanStack Table, ADR-0008) is the eventual flat-row option.
Related: [[feedback-full-fidelity-ports]] (don't ship partial ports), [[project-mtp-component-authoring]] (use <Sidebar>/<ThreePane> for page layout, never hand-roll the column split).