Try fixing minitable truncation with CSS grid instead#3293
Open
david-crespo wants to merge 1 commit into
Open
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
david-crespo
force-pushed
the
grid-minitable-truncate
branch
from
July 17, 2026 23:41
ea7c759 to
d93c22a
Compare
david-crespo
commented
Jul 18, 2026
| onMouseEnter={() => { | ||
| const el = ref.current | ||
| setIsTruncated(!!el && el.scrollWidth > el.clientWidth) | ||
| }} |
Collaborator
Author
There was a problem hiding this comment.
this is ingenious what the hell
david-crespo
commented
Jul 18, 2026
| tabIndex={0} | ||
| aria-rowindex={index + 1} | ||
| key={rowKey(item, index)} | ||
| className="bg-default before:border-default relative col-span-full grid grid-cols-subgrid pt-2 before:pointer-events-none before:absolute before:inset-0 before:border-x before:content-[''] last:pb-2 last:before:rounded-b-lg last:before:border-b" |
Collaborator
Author
There was a problem hiding this comment.
I think all this horrible stuff would be better as CSS. I’ll give it a try.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Alternative to #3182 proposed by Fable.
🤖 Fable comparison to #3182
Everything needed is in hand: both implementations, both PR discussions, the PR screenshots, and the notes from the previous session (
.claude/notes/2026-07-17-minitable-grid-rewrite.md). No browser needed — the April screenshots on #3182 demonstrate the key differentiating scenario directly, and the clamp logic they illustrate is unchanged after the rebase.Elegance
The two branches converge on an identical public API (
textvscellcolumns, truncate-with-tooltip via the same scrollWidth check). The difference is entirely in how column widths get decided.Measurement branch (#3182, +185/−20): canvas
measureTextper cell → clamp ratios to 2.5:1 viasqrt(5/2)→ normalize to percentage widths. Its main structural weakness is that it re-derives layout outside the layout engine, and has to defeat the layout engine to do it: every text cell is absolutely positioned (absolute inset-x-3) specifically so content can't influence native table sizing, then JS reconstructs what the sizes should be from a canvas measurement. Supporting apparatus follows from that choice:text-width.ts, a hand-copied'400 14px SuisseIntl'/0.03remfont spec that must shadowtext-sans-md, the spread/floor/ceiling heuristic, and a memoization contract that leaks into the API ("keep this array referentially stable"). On the plus side, it keeps genuine table display semantics and reusesTable.Header/Table.HeadCellfrom the big table.Grid branch (#3293, +178/−175, net ~0 against main): the whole sizing policy is one declarative expression —
minmax(0, auto)for text columns,max-contentfor cell columns — and the browser computes widths from the actual rendered glyphs. It deletestext-width.ts, the font constants, the clamp, the memo contract, and all 85 lines ofmini-table.cssnth-child tricks (styles now co-located). The cost is an ARIA tax:display: grid/display: contentsstrip implicit table semantics, so every element carries an explicit role and the file needs two jsx-a11y eslint disables. It also re-implements header-cell chrome inline rather than reusingTable.HeadCell— though main's css file was already a parallel implementation, so that's not a regression, just a missed reuse the other branch gets.On elegance the grid version wins on the axis that matters most here: the measurement branch simulates the layout engine; the grid branch instructs it. Benjamin explicitly identified container-aware sizing as the ideal in the PR thread ("This could be even more clever by using absolute pixel widths and being container aware… But I'm not sure it's worth the extra complexity") — the grid gets exactly that behavior for free, because it's the layout engine's native job.
Scenarios with clearly different results
1. Long name next to short columns, with slack in the table — grid clearly better. This is the case users actually hit (#2999). The measurement floor reserves ~22% for each short column and the ceiling caps the long one at ~56%, so a long name truncates while its neighbors sit half empty. The NIC screenshot in the #3182 thread shows exactly this:
asdasdasd-asdasdas…cut off whilemock-vpcandmock-subneteach float in ~2× the width they need. Concretely: a name measuring 300px next to two trivial columns in a 512px table gets 55.6% ≈ 285px under measurement (truncated, ~200px dead space nearby); under grid the row's max-contents sum to well under 512, so the full name renders. A grid track never truncates while slack exists anywhere in the row.2. First paint before the webfont loads, or future font changes — grid correct by construction.
measureTextagainstSuisseIntlbefore the font loads measures the fallback font, and nothing re-measures on font load; likewise, any future change totext-sans-mdor letter-spacing silently desyncs the hardcoded constants. The grid version has no measurement to get wrong. Low frequency in practice (MiniTables appear after user interaction), but it's an entire bug class one approach can have and the other can't.3. Short content everywhere — grid modestly better. Compare the two "abc" disk screenshots on #3293: grid lets badge columns hug content and gives leftover to the name; measurement stretches every text column to its clamped percentage, so dividers land disconnected from content (visible in the
asdaNIC screenshot on #3182). Cosmetic, but consistently in grid's favor.4. Two long text columns under real constraint — different, neither clearly better. This is the one behavioral fork that's genuinely a matter of taste. Grid's track sizing is max-min water-filling: width distributes equally, short tracks freeze at content size, so the longest column absorbs all of the shortage beyond its equal share. Measurement shrinks proportionally (clamped), spreading the pain. Example: contents of 350px and 220px sharing 400px — grid yields 200/200 (shorter column 91% visible, longer 57%); measurement yields ~245/155 (both ~70% visible). Reasonable people could prefer either.
5. Legacy assistive tech — measurement clearly better, in principle. It's the only scenario found where measurement wins: it keeps real table display semantics, while grid depends on explicit ARIA roles to patch over
display: contentssemantics-stripping, which was historically buggy in browsers (fixed in current engines, and the role-based Playwright locators pass per the prior session's e2e runs). If the console had to support an old AT/browser combination, that would favor #3182; given the console's modern-browser baseline, it's a theoretical edge.Verdict
Grid dominates on rendered results in the scenarios users encounter (1–3); its costs are confined to the code (ARIA boilerplate, subgrid idiom, duplicated header chrome) rather than the output. The measurement branch's advantages are semantic purity that its own absolute-positioning hack partially undermines, and a taste-based difference in how two simultaneously-truncating columns split the shortage. If presenting this on the PRs, scenario 1 is the strongest exhibit — the #3182 thread's own screenshots demonstrate the truncate-despite-slack behavior, and Benjamin's "container aware… not worth the extra complexity" comment frames the grid version as delivering the behavior he wanted at negative net complexity.
main
This PR