Skip to content

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

Description

@magraina

Provide a general summary of the issue here

When nesting <Tabs> inside another <Tabs> component, the transition animations severely break and can cause cause large layout shifts, when switching the outer <Tabs> component. This is caused by three distinct issues interacting with each other.

🤔 Expected Behavior?

  1. Nested TabPanels should not inherit transition CSS variables from parent TabPanels. (Perhaps the TabPanels should set these variables initially, or TabPanel should reset them to auto for nested childs).

Workaround:

.react-aria-TabPanels {
  position: relative;
  height: var(--tab-panel-height);
  width: var(--tab-panel-width);
  /* .... */
}

.react-aria-TabPanel {
  padding: var(--spacing-3);
  border-radius: var(--radius);
    /* .... */

  --tab-panel-width: auto; /* <-- Reset the variable for nested TabPanels */
  --tab-panel-height: auto;
}
  1. Outer TabPanels measuring logic should either wait for nested collections to finish building, or TabList should hold its space synchronously or TabList should hold on to a at least a minimum size.
    Workaround: Setting a hard min-height on the TabList CSS class to reserve the space during the initial render.

  2. At least mentioning somewhere that this is needed.
    Workaround: Explicitly providing defaultSelectedKey to the nested <Tabs> so the inner <TabPanel> mounts synchronously

😯 Current Behavior

Issue 1: CSS Variable Inheritance (Bleed)

The outer <TabPanels> applies inline styles for --tab-panel-height and --tab-panel-width to handle transitions. However, CSS Custom Properties inherit downwards.
When a nested <TabPanels> mounts, it does not have set a inline style for --tab-panel-height and --tab-panel-width. So while the transformation is ongoing the nested <TabPanels> applies the values of the outer <TabPanels> which are bigger than they should.
It ends up temporarily inheriting the parent's explicit pixel height, throwing off the layout.
This issue happens not always as the TabPanels seems not always set the CSS custom properties and it

Issue 2: TabList has 0 height on initial render

When the nested <Tabs> component mounts while switching the Tab on the outer Tabs component, the inner <TabList> initially renders with 0px height.
This causes the transition logic to calculate the wrong height for the transition. Which causes a layout shift right after the transition, which is exactly the height of the <TabList>

Issue 3: TabPanel has 0 height oninitial render

When the nested <Tabs> component mounts, if defaultSelectedKey is not explicitly provided, the component takes one render frame to determine the active tab. During this frame, the nested <TabPanel> renders with 0px height. This causes the transition logic to calculate the wrong height for the transition. Which causes a large layout shift right after the transition, which is exactly the height of that <TabPanel>

💁 Possible Solution

No response

🔦 Context

Trying to setup a layout that needs to have nested Tabs.

🖥️ Steps to Reproduce

StackBlitz
Switch between the Tabs on the upper Tabs element (parent) in the Preview:

  • Switch form the first General to the second Tab Appearance and notice normal behavior (This is the one I have modified with min-height on TabList and and `defaultSelectedKey``)
  • Switch back to the first Tab General and notice the radical change on the layout within the transition.
  • Switch to the third Profile Tab and notice the text and the input fields on the nested Tab shifting in size because the container is changing the size (Noticeable shift on the text might be depending on preview window size - try changing it if you cant notice it).
  • Switch back to the second Appearance Tab
  • Switch to the last Tab Notifications and notice normal behavior (This is the one where I have added a class to the parents TabPanel to stop inheriting the wrong css variable)

Version

react-aria: 3.50.0 - react-aria-components: 1.19.0

What browsers are you seeing the problem on?

Chrome

If other, please specify.

No response

What operating system are you using?

Windows

🧢 Your Company/Team

No response

🕷 Tracking Issue

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomers

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions