Skip to content

fix: Reset TabPanels size variables on TabPanel so nested Tabs do not inherit them#10293

Open
mvanhorn wants to merge 3 commits into
adobe:mainfrom
mvanhorn:fix/10292-nested-tabs-css-variable-bleed
Open

fix: Reset TabPanels size variables on TabPanel so nested Tabs do not inherit them#10293
mvanhorn wants to merge 3 commits into
adobe:mainfrom
mvanhorn:fix/10292-nested-tabs-css-variable-bleed

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Nested TabPanels inherit the parent's inline --tab-panel-width / --tab-panel-height pixel values while they mount, because CSS custom properties inherit and unset cannot stop that (for inherited properties it means inherit). With the documented .react-aria-TabPanels { height: var(--tab-panel-height) } pattern, a freshly mounted inner TabPanels sizes itself from the outer panel's measurements and the height transition jumps.

TabPanelInner now sets --tab-panel-width: auto and --tab-panel-height: auto on its dom.div (the reset point snowystinger suggested in the issue), so the variables stop at the panel boundary and a nested TabPanels measures cleanly. User-provided inline styles are spread after the reset and still win. The two 0-height initial-render reports in the same issue are separate timing problems in the async collection build and are not touched here.

Closes #10292

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component). N/A: no documented behavior changes; the height-transition pattern in the TabPanels docs works as written once the variables stop inheriting.
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

Run yarn jest packages/react-aria-components/test/Tabs.test.js. The new tests render nested Tabs mid-transition and assert the inner panel's --tab-panel-width / --tab-panel-height resolve to auto rather than the outer panel's pixel values, and that a user style passed to TabPanel still overrides the reset. To reproduce manually, nest a Tabs inside a TabPanel with the height-transition CSS from the TabPanels docs and switch tabs: without the reset the inner panels flash to the outer panel's height.

🧢 Your Project:

Personal open source contribution

@snowystinger snowystinger left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How did you verify that this worked in a browser to a satisfactory degree? I don't see a story to test it with.

Comment on lines +631 to +632
'--tab-panel-width': 'auto',
'--tab-panel-height': 'auto',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'--tab-panel-width': 'auto',
'--tab-panel-height': 'auto',
'--tab-panel-width': 'unset',
'--tab-panel-height': 'unset',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See reasoning here: #10292 (comment)

Address @snowystinger's request for a browser-testable story: the existing
NestedTabs story does not apply the size-transition CSS, so it never exercises
the --tab-panel-width/height inheritance. Add a story that puts an
animated-tabpanels class (consuming those vars with a width/height transition)
on both an outer and a nested TabPanels, so the bleed is observable in
Storybook/Chromatic - without the per-TabPanel reset the inner panels inherit
the outer TabPanels' pixel vars; with it they size to their own content.
@mvanhorn

mvanhorn commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Added a NestedTabsSizeTransition story (Tabs.stories.tsx) and ran it in Storybook locally to verify. The size-transition CSS (var(--tab-panel-width/height) with a transition) is applied to both an outer and a nested TabPanels.

Verified in the browser via DOM inspection: with the fix, every react-aria-TabPanel gets inline --tab-panel-width: auto; --tab-panel-height: auto, which breaks the custom-property inheritance so a nested TabPanels can't pick up the parent's transient pixel values; reverting the fix removes that reset.

One thing worth flagging: TabPanels only sets those vars during the resize animation and clears them at rest, so the bleed is a transition-time effect. The story exercises it when you switch tabs and watch the nested panel animate, rather than as a static snapshot difference. Happy to tune the scenario if you want it to show more starkly.

@devongovett

Copy link
Copy Markdown
Member

alternatively we could do CSS.registerProperty({name: '--tab-panel-width'}) (inherits is false by default).

@mvanhorn

mvanhorn commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Went with @devongovett's suggestion — registered --tab-panel-width/--tab-panel-height via CSS.registerProperty with inherits: false, so nested panels no longer inherit the outer panel's size vars. Kept @snowystinger's unset reset as a fallback for environments without CSS.registerProperty (SSR/jsdom), and updated the tests to match. Local jest (44/44), type-check, and format all pass. Thanks both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nested Tabs height transitions break due to CSS variable bleed and 0-height behavior of TabList and TabPanel

3 participants