Skip to content

fix(react-ui): don't auto-select the last tab on Tabs initial mount#820

Open
Shinyaigeek wants to merge 1 commit into
thesysdev:mainfrom
Shinyaigeek:fix/tabs-initial-tab-selection
Open

fix(react-ui): don't auto-select the last tab on Tabs initial mount#820
Shinyaigeek wants to merge 1 commit into
thesysdev:mainfrom
Shinyaigeek:fix/tabs-initial-tab-selection

Conversation

@Shinyaigeek

Copy link
Copy Markdown
Contributor

Fixes #819

Problem

<Tabs> selects the last tab on initial mount instead of the first, even for a fully static (non-streaming) response.

Standalone repro against the published packages: https://github.com/Shinyaigeek/openui-tabs-repro

The dependency-less auto-advance effect (streaming follow-along) runs its first pass with prevContentSizes.current empty, so every tab satisfies size > prevSize and candidate ends the loop at the last item. It runs in the same commit as — and after — the effect that defaults activeTab to the first tab, so the last tab wins.

Fix

Treat the first pass as a baseline-recording pass: record nextSizes but skip candidate selection when prevContentSizes.current is empty.

Streaming follow-along is unaffected:

  • content growth relative to the recorded baseline still advances the active tab;
  • a tab that appears after the first pass has no baseline entry, so its content counts as growth and still advances.

Verification

Rendered via a vite harness aliased to react-ui source, before/after:

Scenario Before After
Static 3-tab mount last tab (Cherry) active first tab (Apple) active
Streamed 3-tab response (12 chars / 150 ms) follows growing tab, ends on Cherry same — ends on Cherry

Before: before

After (top: static mount now Apple; bottom: streaming control still ends on Cherry): after

pnpm test (react-ui): 13 passed. lint:check: 0 errors. typecheck failures in UserMessageContent.tsx / index.ts are pre-existing on main (verified by stashing this change).

🤖 Generated with Claude Code

The dependency-less auto-advance effect in Tabs treats every tab as
"grown" on its first pass (prevContentSizes starts empty), so candidate
ends the loop at the last item and overrides the first-tab default set
by the mount effect in the same commit. A static three-tab response
therefore mounts with the last tab active instead of the first.

Record the first pass as a baseline only and skip candidate selection.
Streaming follow-along is unaffected: content growth relative to the
baseline, or a tab appearing after the first pass, still advances the
active tab.

Fixes thesysdev#819

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tabs selects the last tab on initial mount instead of the first

1 participant