[go_router] Fix ShellRoute chrome dropped from semantics tree by ModalBarrier - #12353
Open
davidmigloz wants to merge 2 commits into
Open
[go_router] Fix ShellRoute chrome dropped from semantics tree by ModalBarrier#12353davidmigloz wants to merge 2 commits into
davidmigloz wants to merge 2 commits into
Conversation
…lBarrier Every ModalRoute (e.g. the MaterialPageRoute go_router builds for each GoRoute) creates a ModalBarrier wrapped in BlockSemantics, which drops the semantics of siblings painted before it up to the nearest semantics boundary. A nested Navigator (as built for ShellRoute/StatefulShellRoute branches) does not itself establish a semantics boundary, so the block escapes the shell's Navigator and drops earlier-painted shell chrome, e.g. a side-rail or app bar in a Row/Column-based shell. Bottom-nav shells are unaffected only because Scaffold happens to paint its body before its chrome. Wraps the Navigator built for ShellRoute/StatefulShellRoute branches (but not the root GoRouter navigator, which has no earlier-painted siblings by construction) in Semantics(container: true) to contain the block. This is the workaround independently confirmed by a Flutter framework team member on the upstream issue. Fixes flutter/flutter#135656 Related: flutter/flutter#150978
…dary StatefulShellRoute branches flow through the same _buildPageForShellRoute path as ShellRoute, so they are already covered by the Semantics(container: true) fix, but no test proved it. Adds a test to the existing 'Shell navigator semantics boundary' group using StatefulShellRoute.indexedStack, mirroring the ShellRoute chrome test.
Contributor
There was a problem hiding this comment.
Code Review
This pull request updates go_router to wrap nested navigators for ShellRoute and StatefulShellRoute in a Semantics widget with container: true. This change ensures that shell chrome painted before the navigator is not dropped from the semantics tree by the active route's ModalBarrier. Unit tests verifying this behavior and a pending changelog entry have also been added. As there are no review comments, no further feedback is provided.
davidmigloz
added a commit
to davidmigloz/flutter_packages
that referenced
this pull request
Aug 3, 2026
…lBarrier Every ModalRoute builds a ModalBarrier wrapped in BlockSemantics, which drops the semantics of siblings painted before it up to the nearest semantics boundary. The nested Navigator built for ShellRoute/StatefulShellRoute branches establishes no such boundary, so the block escapes it and prunes earlier-painted shell chrome (side rail, app bar in Row/Column shells). Wraps shell navigators (not the root navigator) in Semantics(container: true) to contain the block. Squash of the two commits on the upstream PR branch: flutter#12353 Fixes flutter/flutter#135656
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Shell chrome painted before a
ShellRouteorStatefulShellRoutenavigator (a side rail, or an app bar in aRow/Columnbased shell) disappears from the semantics tree. Screen readers cannot reach it at all: the nodes are not merely unnamed, they do not exist.The mechanism: every
ModalRoutebuilds aModalBarrierwrapped inBlockSemantics, which drops the semantics of everything painted before it up to the nearest semantics boundary. The nestedNavigatorthat go_router builds for shell routes does not establish such a boundary, so the block escapes the shell's navigator and prunes the shell's own chrome. Bottom-nav shells are unaffected only becauseScaffoldhappens to paint its body before its bars.This PR wraps the navigator built for
ShellRoute/StatefulShellRoutebranches inSemantics(container: true), which contains the block. The root navigator is left unwrapped, since it has no earlier-painted siblings by construction. This is the workaround a framework team member confirmed on the linked issue; applying it inside go_router fixes it for every shell consumer without app-side patches.Semantics tree of a minimal repro (a
Rowshell: 220px sidebar with three nav buttons, routed content on the right), before and after, captured withdebugDumpSemanticsTree:Before: 6 nodes, the entire sidebar subtree is missing
Node
#3starts atx=221, right of the 220px sidebar plus a 1px divider. There is no node anywhere for the sidebar: no title, no navigation container, no buttons. The sidebar is painted before the/dashboardroute (#4,scopesRoute) inside the same enclosing semantics scope, which is exactly what that route'sBlockSemanticsdrops.After: sidebar fully present, routed content unchanged (two nodes for the repro's own toggle switch omitted for brevity)
The routed content node ("Dashboard content") is byte-identical in both dumps. The fix does not change the routed content's semantics, only whether the chrome painted before the shell navigator survives alongside it.
Notes for review:
Shell navigator semantics boundarygroup tobuilder_test.dart(chrome survives, structural wrap present, root navigator not wrapped), and a second commit adds aStatefulShellRoute.indexedStackregression test covering branch switching. Removing the wrap makes the chrome tests fail withFound 0 widgets with a semantics label.pending_changelogs/(version: patch) instead of touchingpubspec.yamlorCHANGELOG.md.BlockSemanticsin modal routes withAccessibilityFocusBlockType.blockSubtree): the fix establishes a semantics container boundary at the shell navigator, which is where a nested navigator should scope its routes' blocking regardless of the blocking mechanism. If that migration later makes the containment unnecessary, the wrap stays harmless.Fixes flutter/flutter#135656
Related: flutter/flutter#55758, flutter/flutter#150978
Pre-Review Checklist
[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2