fix: preserve active tab selection after spinner reruns#14023
fix: preserve active tab selection after spinner reruns#14023sfc-gh-bnisco merged 1 commit intodevelopfrom
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
✅ PR preview is ready!
|
SummaryThis PR fixes a bug (#14018) where tabs lose their selection state when rendered after a The fix adds a 4-line unwrap in Code QualityThe fix is minimal, well-placed, and follows existing patterns in the codebase.
Test CoverageThe changes are well-covered:
Backwards CompatibilityNo breaking changes. The fix only changes behavior when a Security & RiskNo security concerns. This is a client-side render-tree state management fix with no impact on data handling, authentication, or network communication. The change is narrow in scope and low risk. AccessibilityThe fix is a net positive for accessibility: tab selection state is now correctly preserved across reruns when tabs follow a spinner context. This means keyboard/screen-reader users who select a tab won't have their selection unexpectedly reset after a rerun. RecommendationsNo blocking issues. Minor observations:
VerdictAPPROVED: Clean, minimal fix for a real user-reported regression with strong unit and E2E test coverage. The change is safe, backwards-compatible, and follows existing codebase patterns. This is an automated AI review by |
There was a problem hiding this comment.
Pull request overview
This PR fixes a regression introduced in Streamlit v1.53 where tab selection state was lost when tabs were rendered after a spinner context. The root cause was that TransientNode wrappers (used by spinners) weren't being properly unwrapped when checking for child inheritance during block replacement.
Changes:
- Modified
AppRoot.addBlock()to unwrap TransientNodes and use their anchor node for child inheritance decisions - Added comprehensive unit test verifying child inheritance when replacing blocks wrapped in transient nodes
- Added E2E regression test confirming tab selection preservation after spinner completion
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
frontend/lib/src/render-tree/AppRoot.ts |
Fixed child inheritance logic to unwrap TransientNodes and use their anchor node when replacing blocks |
frontend/lib/src/render-tree/AppRoot.test.ts |
Added unit test verifying that tab children are properly inherited when replacing a block wrapped in a transient node |
e2e_playwright/st_spinner_test.py |
Added E2E test verifying tab selection and widget interaction work correctly after spinner completes |
e2e_playwright/st_spinner.py |
Added test scenario reproducing the bug: spinner followed by tabs with widgets |
dfbdd0d to
63c3dd3
Compare
## Describe your changes Fixed a bug where tabs would lose their selection state when rendered after a spinner context. The issue occurred because transient nodes (like spinners) weren't properly handling child inheritance during reruns. The fix modifies the AppRoot class to check if a node is a TransientNode and use its anchor node for child inheritance when replacing blocks. This ensures that tab selection state is preserved across reruns when tabs are rendered after a spinner. ## Screenshot or video (only for visual changes) ## GitHub Issue Link (if applicable) Fixes #14018 ## Testing Plan - Unit Tests (JS and/or Python) - Added a unit test in AppRoot.test.ts to verify that children are properly inherited when replacing a block wrapped in a transient node - E2E Tests - Added a regression test scenario in st_spinner.py that reproduces the issue with tabs after a spinner - Added a corresponding test in st_spinner_test.py that verifies tab selection is preserved after widget interaction --- **Contribution License Agreement** By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

Describe your changes
Fixed a bug where tabs would lose their selection state when rendered after a spinner context. The issue occurred because transient nodes (like spinners) weren't properly handling child inheritance during reruns.
The fix modifies the AppRoot class to check if a node is a TransientNode and use its anchor node for child inheritance when replacing blocks. This ensures that tab selection state is preserved across reruns when tabs are rendered after a spinner.
Screenshot or video (only for visual changes)
GitHub Issue Link (if applicable)
Fixes #14018
Testing Plan
Unit Tests (JS and/or Python)
E2E Tests
Contribution License Agreement
By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.