Tabs: indicator pop-in animation never runs — data-[rendered=false] styles are dead against Base UI 1.6
- Dominant language
- TypeScript
- Stars
- 3.9k
- Forks
- 177
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 48
Description
## Summary
On initial mount, the Tabs indicator (both segmented pill and underline variants) appears instantly at full opacity. The intended pop-in — `scale-90 → scale-100` + `opacity-0 → opacity-1` over 200ms — never runs.
## Root cause
The indicator in `packages/kumo/src/components/tabs/tabs.tsx` is styled with:
```
data-[rendered=false]:scale-90 data-[rendered=false]:opacity-0
```
but Base UI's `TabsIndicator` (v1.6.0) never sets a `data-rendered` attribute, so these rules are dead CSS — the element is painted at full opacity/scale from its first frame.
For the record, Base UI does correctly avoid the 0×0 flash: it measures the active tab during render and keeps the element `hidden` until `isTabSelected && width > 0 && height > 0`. Only the pop animation is missing.
## Expected
Indicator pops in at the correct size/position (scale 0.9 → 1, opacity 0 → 1, ~200ms), as the dead classes suggest was intended — never animating its size from 0, never appearing instantly.
## Suggested approaches
1. Drive `data-rendered` from a small piece of state: start `false`, flip to `true` on a later frame after the first measurement (e.g. double `requestAnimationFrame` from a mount effect), guaranteeing one painted frame at the pre-pop state so the CSS transition actually runs.
2. Or drop the dead classes and use `@starting-style` + `transition-behavior: allow-discrete` (modern browsers only).
## Environment
- `@base-ui/react` ^1.6.0
- `main` @ 65db2e6
Contributor guide
Research direction
Start in packages/kumo/src/components/tabs/tabs.tsx and trace how the Tabs indicator is rendered and styled against Base UI 1.6. Implement a reliable first-render trigger for the existing pop-in behavior, then verify that both segmented-pill and underline indicators transition from scale 0.9 and opacity 0 to their full state over about 200ms without a size flash or instant appearance.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 74/100