adobe / adobe/react-spectrum

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

Open
#10,292 12 comments 0 reactions 0 assignees View on GitHub
bug good first issue
Dominant language
TypeScript
Stars
15.9k
Forks
1.6k
Avg merge
3d 9m
Merged PRs (30d)
59

Description

### Provide a general summary of the issue here

When nesting `` inside another `` component, the transition animations severely break and can cause cause large layout shifts, when switching the outer `` 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:**
```css
.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;
}
```

2. 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.

3. At least mentioning somewhere that this is needed.
**Workaround:** Explicitly providing `defaultSelectedKey` to the nested `` so the inner `` mounts synchronously

### 😯 Current Behavior

#### Issue 1: CSS Variable Inheritance (Bleed)
The outer `` applies inline styles for `--tab-panel-height` and `--tab-panel-width` to handle transitions. However, CSS Custom Properties inherit downwards.
When a nested `` 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 `` applies the values of the outer `` 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 `` component mounts while switching the Tab on the outer `Tabs` component, the inner `` 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 ``

#### Issue 3: `TabPanel` has 0 height oninitial render
When the nested `` component mounts, if `defaultSelectedKey` is not explicitly provided, the component takes one render frame to determine the active tab. During this frame, the nested `` 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 ``

### 💁 Possible Solution

_No response_

### 🔦 Context

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

### 🖥️ Steps to Reproduce

[StackBlitz](https://stackblitz.com/edit/8ypukkum?file=src%2FExample.tsx)
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_

Contributor guide

Open the contributing guide

Research direction

Start with the StackBlitz reproduction in src/Example.tsx using the reported react-aria 3.50.0 and react-aria-components 1.19.0 versions. Reproduce nested Tabs while switching the outer tabs, then verify that nested panels no longer inherit incorrect CSS variables and that TabList and TabPanel height transitions do not cause layout shifts or require the documented workarounds.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.