Skip to content

feat(layout)!: the shell's content box no longer scrolls; pages scroll themselves - #166

Merged
anilcancakir merged 2 commits into
mainfrom
feat/content-box-does-not-scroll
Sep 24, 2026
Merged

anilcancakir merged 2 commits into
mainfrom
feat/content-box-does-not-scroll

Conversation

@anilcancakir

Copy link
Copy Markdown
Member

What

  • Breaking: MagicStarterLayoutTheme.contentClassName defaults to 'flex-1 min-h-0' and contentScrollPrimary to false (previously 'flex-1 overflow-y-auto' and true). The shell's content box no longer scrolls, and each routed page scrolls itself.
  • The notification screens take the host page geometry through their contentClassName, inside their own scroll view, rather than wrapped in MSPageContainer.
  • The starter:install dashboard stub gets its own scroll view.
  • The theme docs, doc/basics/views-and-layouts.md and three comments now describe the new shape. The CHANGELOG has a ### Breaking entry with migration steps and one known loss.

Why

In a go_router shell the route child is the nested Navigator, so the old default scrolled the Navigator and laid its Overlay out under an unbounded height. A page left under a .stacked() route was then never laid out again, and its second rebuild while hidden failed _debugRelayoutBoundaryAlreadyMarkedNeedsLayout in debug and left the tree inconsistent. Closes #160; upstream is flutter/flutter#193247, reproduced in a fresh app, with a SizedBox.expand control that stays clean.

Testing

  • New test: a go_router ShellRoute on MagicStarterAppLayout, with a list and a pushed detail, and the hidden list rebuilt three times. Red on the old default with the assertion, green on the new one.
  • New notification-routes test: each screen's scroll view fills the page, so the padding scrolls with the content. Red before the geometry move (a 32px inset), green after. The width cap is now measured on the capped column.
  • Three tests that pinned the old default now exercise the scrolling box as an explicit opt-in.
  • flutter analyze clean, 1552 tests green, dart format --set-exit-if-changed . clean.

Downstream

  • uptizm is unaffected: it registers its own layout.app.
  • magic_example uses the default shell, and its DashboardView has no scroll view of its own. A matching PR in that repository wraps it.
  • Lost: tapping the iOS status bar no longer scrolls a shell page to the top, because nothing is attached to the primary controller above the nested Navigator any more. This is noted in the CHANGELOG; restoring it is a separate change.

…l themselves

In a go_router shell the route child is the nested Navigator, so the
default 'flex-1 overflow-y-auto' content box scrolled the Navigator and
laid its Overlay out under an unbounded height. A page left under a
.stacked() route was then never laid out again, and its second rebuild
while hidden failed _debugRelayoutBoundaryAlreadyMarkedNeedsLayout in
debug and left the tree inconsistent.

contentClassName now defaults to 'flex-1 min-h-0' and
contentScrollPrimary to false. Every view the package ships already
scrolls itself, so none of the starter's own screens moves. A host page
that relied on the shell to scroll it needs its own scroll view or
MSPageScaffold, or the old pair set back; the CHANGELOG and the layout
doc cover both.

Closes #160
…ling

Review follow-up on the content box change. The notification screens
were wrapped in MSPageContainer, whose top and bottom padding sat
outside their own scroll view: under a content box that no longer
scrolls, that padding inset the viewport and a long list clipped at a
hard line. The host geometry now travels as the views' contentClassName,
which lands inside their scroll. The starter:install dashboard stub had
no scroll at all and now has its own.

The CHANGELOG entry moves under a Breaking heading as earlier breaking
releases did, names the two screens that changed and the iOS
status-bar tap-to-top this loses, and three comments stop describing
the shell's scroll container.
@codecov

codecov Bot commented Sep 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@kodizm

kodizm Bot commented Sep 24, 2026

Copy link
Copy Markdown

Note

Kodizm (AI-generated). May contain mistakes; verify before acting.

The change looks correct. I found nothing to fix before merging. The break is deliberate, and the CHANGELOG, the docs and the tests all cover it.

I checked these points:

  • Starter screens still scroll. MSPageScaffold screens already scroll themselves, and so does the invitation card (fix(teams): the invitation-accept screen scrolls itself #164). The two notification screens now get the geometry from pageContainerRecipe(hostClassName: …) and apply it inside their own scroll view. So the non-scrolling flex-1 min-h-0 box doesn't leave any shipped screen without a scroll.
  • Dropping MSPageContainer from the notification mount loses nothing. That wrapper added a horizontal-only SafeArea. The shell's body already sits in a SafeArea(bottom: false) (lib/src/ui/layouts/magic_starter_app_layout.dart:244), and those routes never use the immersive branch, so the left and right insets are still handled.
  • The starter:install stub still compiles. dashboard_view.stub already imports package:flutter/material.dart, so its new SingleChildScrollView(primary: false) resolves. Only the indentation and the new outer wrapper changed.
  • Repo rules are followed. The CLAUDE.md post-change checklist (CHANGELOG under [Unreleased] and a doc/ update) is met. The README doesn't mention these fields.
  • Known loss. The PR says tapping the iOS status bar no longer scrolls a shell page to the top, and the CHANGELOG says so too. That is a product decision, not a defect.

The downstream magic_example DashboardView depends on the companion PR the description mentions. Until that PR lands, the example renders cut off at the window. It lives in another repository, so it is outside this review.

Tests

There is a new go_router ShellRoute regression test in which a hidden page is rebuilt three times under a pushed route. A new test checks that each notification screen's scroll view fills the page. The three earlier tests of the old default now opt into the scrolling box explicitly, and the default-value test now expects flex-1 min-h-0 / false.

CI

  • Lint & Test: success
  • Published graph: success
  • codecov/patch: success
  • Auto-merge low-risk Dependabot PRs: skipped

anilcancakir added a commit to fluttersdk/magic_example that referenced this pull request Sep 24, 2026
magic_starter's app shell stops scrolling its content box
(fluttersdk/magic_starter#166): a scroll around the shell's nested
Navigator broke a page left under a stacked route. Under the new
default a page taller than the window scrolls itself, and this one had
no scroll of its own. Under the old default the inner scroll sizes to
its content and claims no drag, so this lands safely either way.
@anilcancakir
anilcancakir merged commit 9ee165a into main Sep 24, 2026
5 checks passed
@anilcancakir
anilcancakir deleted the feat/content-box-does-not-scroll branch September 24, 2026 10:18
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.

Default app shell scrolls the nested Navigator, so a page under a stacked route breaks on its second hidden rebuild

1 participant