Repository navigation
fix: stabilize resizable tables in nested flex layouts - #10715
minwookshin wants to merge 4 commits into
Conversation
|
Scoped the keyboard test’s input to its document; the full Linux Firefox suite passes locally. The PR notes the separate WebKit failures and unmodified-base check. |
|
The columns used the full container width without accounting for table spacing and borders, which could keep increasing the measured width in a flex layout. The patch subtracts that extra space and uses border-box sizing for the columns. |
snowystinger
left a comment
There was a problem hiding this comment.
I think we're going to need a different approach given the box-sizing, what other options did you think about? I am not excited about how many specific things need to be measured here. I'll continue to mull it over as well.
| let style = renderProps.style; | ||
| if (layoutState) { | ||
| style = {...style, width: layoutState.getColumnWidth(column.key)}; | ||
| style = {...style, boxSizing: 'border-box', width: layoutState.getColumnWidth(column.key)}; |
There was a problem hiding this comment.
This would be a breaking change, it will change how peoples tables are currently laid out
| let onColumnsChange = tableContainerContext?.onColumnsChange; | ||
| let columnCount = filteredState.collection.columns.length; | ||
| useLayoutEffect(() => { | ||
| onColumnsChange?.(columnCount); |
There was a problem hiding this comment.
This feels unrelated to the resizing? When does the table filtering change the number of visible columns?
|
Agreed, forcing |
|
Reworked this to measure the table's extra width without changing column |
snowystinger
left a comment
There was a problem hiding this comment.
Thanks for trying out something new
| let onResize = () => onResizeEvent(); | ||
| window.addEventListener('resize', onResize, false); | ||
| return () => { | ||
| window.removeEventListener('resize', onResizeEvent, false); | ||
| window.removeEventListener('resize', onResize, false); |
| ref: RefObject<T | undefined | null> | undefined; | ||
| box?: ResizeObserverBoxOptions; | ||
| onResize: () => void; | ||
| onResize: (entry?: ResizeObserverEntry) => void; |
There was a problem hiding this comment.
I think if we're going to add this, we should add all the entries, just like resize observer. though I'd really prefer not to do it
| onResize={onResize} | ||
| onResizeEnd={onResizeEnd}> | ||
| <Table aria-label="Files" {...otherProps}> | ||
| <Table aria-label="Files" style={{borderSpacing: 0}} {...otherProps}> |
There was a problem hiding this comment.
why? is this necessary? if so, that would indicate there's still a breaking change
| let updateWidth = useCallback((entry?: ResizeObserverEntry) => { | ||
| let width = scrollRef.current?.clientWidth ?? 0; | ||
| let table = tableRef.current; | ||
| if (table?.tagName === 'TABLE') { |
There was a problem hiding this comment.
what if something is a DIV with display: table? or inline-table?
| : 0; | ||
| onColumnWidthsChange?.(allocatedWidth); | ||
| }, [onColumnWidthsChange, columnWidths]); | ||
|
|
There was a problem hiding this comment.
don't love this, it's going to be a render late and introduce a new render
I'm assuming this was to solve whatever the issue was with counting columns? can you explain more about the problem here?
There was a problem hiding this comment.
The sum handles fixed/percentage widths and different box sizing; column count isn't enough. I kept the corrective render before paint because Firefox misses consecutive collection changes through ResizeObserver alone—the 2→3→4→2-column test catches this.
|
Kept the observer local, switched to computed display, and removed both border-spacing overrides. Unit/SSR and all three browser suites pass; details are in the description. |
Closes #5412.
Resizable tables should settle within their available width inside nested flex containers. The scroll viewport's
clientWidthbecomes the column-width budget, but a native table also renders padding, spacing and borders beyond that budget. When its flex ancestor grows to accommodate that extra space, the next measurement can allocate the extra space to columns again.The container now subtracts the difference between the table's rendered border box and the widths allocated by the resize state. This preserves existing column
box-sizinginstead of overriding it and avoids separate formulas for table borders, spacing and cell padding. Column-width changes trigger a measurement, including collection changes whose total width stays the same. A single ResizeObserver local to the container observes both the table and scroll viewport, keeping the shared observer hook unchanged. Its entries provide fractional, untransformed border-box measurements. The correction checks computeddisplayand applies only to intrinsicmin-contenttables; fixed-width virtualized tables retain their existing sizing. Margins and viewport padding are still excluded separately.AI assistance: Codex (GPT-6), following AGENTS.md and the testing, tooling and PR guidance.
✅ Pull Request Checklist:
📝 Test Instructions:
Run
yarn test --runInBand --shard=N/4for each N from 1 to 4,yarn test:ssr, andyarn lint. Runyarn vitest run --config=vitest.browser.config.ts --project=<browser>-desktop --maxWorkers=1 --no-file-parallelismfor Chromium, Firefox and WebKit in turn.Latest follow-up verification: all four Jest shards passed (384 suites, 8,438 tests passed, 16 skipped); SSR passed (60 suites, 74 tests). Type checking, oxlint, formatting, package lint and Yarn constraints all passed, run serially to limit resource use. The old
borderSpacing: 0test overrides have been removed.The 21 table browser tests pass in each browser (63 checks). They cover default content-box and explicit border-box columns, controlled keyboard resizing in LTR/RTL, min/max constraints, fixed/percentage widths, viewport and column-collection changes, spanning body cells, intrinsic sizing with populated/empty bodies, borders, fractional spacing, margins, padding and a scaled ancestor, plus virtualized div tables with
block,tableandinline-tabledisplay.Full browser suites passed: Chromium 176 passed/7 skipped; Firefox 153 passed/30 skipped; WebKit 157 passed/26 skipped. These are the suites' existing skips; no tests were skipped for this change. The previously reported WebKit DropZone failure did not reproduce in this run.
The column-width layout effect is retained deliberately. Column count cannot represent fixed/percentage/min/max widths or content-box padding. An observer-only alternative missed consecutive collection changes in Firefox when the table returned to its previous observed size within a frame; the existing 2→3→4→2-column regression covers this. The corrective measurement runs before paint, with an additional render only when the available column budget changes.
Open React Aria Components → Table → Resizable Flex Table. The table should remain within the 600px flex layout without a
min-width: 0workaround on its ancestors. Existing column padding and box-sizing should remain intact during resizing.This follow-up did not repeat the earlier manual mouse verification. Touch, screen-reader speech and high-contrast visual regression were not manually verified. No Chromatic jobs were triggered.
🧢 Your Project:
Independent open-source contribution.