adaptive_scaffold_router 0.3.1 copy "adaptive_scaffold_router: ^0.3.1" to clipboard
adaptive_scaffold_router: ^0.3.1 copied to clipboard

Adaptive navigation scaffold for Material 3 — drop-in successor to flutter_adaptive_scaffold with first-class go_router support and state preservation.

adaptive_scaffold_router #

Adaptive Material 3 navigation for Flutter that switches BottomNavigationBar → NavigationRail → Drawer by screen size — with first-class go_router support and branch state preserved across breakpoint changes.

A drop-in successor to Google's discontinued flutter_adaptive_scaffold, picking up where it left off.

pub version pub points Flutter license

Resizing the window morphs the navigation while the body state is preserved

One layout, three forms — and the counter keeps its value across every resize.

Why this package? #

Google discontinued flutter_adaptive_scaffold in April 2025 to focus on core framework work — not because it was unpopular (it still gets thousands of downloads a week). It invited the community to make one sustainable fork rather than many one-off forks.

The community forks that appeared mostly added cosmetic options — none solved the two things developers actually hit: go_router integration and state loss on resize. This package does.

flutter_adaptive_scaffold
(discontinued)
Community forks adaptive_scaffold_router
Actively maintained ⚠️
Drop-in AdaptiveScaffold API ⚠️ renamed
go_router integration (flutter#129850)
State preserved across breakpoints
Cupertino bottom bar
Material 3

Everything stays API-compatible with the original, so migrating is a one-line import change.

Features #

  • 📱 Adaptive navigation — bottom bar on phones, rail on tablets, extended rail or a permanent drawer on desktop, with smooth animated transitions.
  • 🗄️ Permanent desktop drawer — opt in with permanentDrawer: true to surface a persistent NavigationDrawer at large widths, the widest tier of the Material 3 navigation progression.
  • 🧭 go_router in a few linesAdaptiveNavigationShell connects StatefulShellRoute.indexedStack to the adaptive layout.
  • 🧠 State preserved across resizes — scroll position, form input and in-memory state survive when the window changes size.
  • 🔁 Drop-in migration from flutter_adaptive_scaffold 0.3.x.
  • 🧩 Low-level building blocksAdaptiveLayout, SlotLayout and Breakpoints are all exposed for full customization.
  • 🪟 Two-pane (list/detail) body + secondaryBody, foldable-aware.

How it works #

Resize the window and the navigation adapts automatically — no manual breakpoint checks needed:

Width Breakpoint Default navigation With permanentDrawer: true
< 600 small Bottom navigation bar Bottom navigation bar
600–840 medium Navigation rail Navigation rail
840–1200 mediumLarge Extended rail Extended rail
1200–1600 large Extended rail Permanent drawer
≥ 1600 extraLarge Extended rail Permanent drawer

Every breakpoint is overridable, and switching tiers only swaps the navigation chrome — the body subtree, and all of its state, stays put. The default desktop navigation is the extended rail (matching flutter_adaptive_scaffold); opt into the permanent drawer with permanentDrawer: true.

Screenshots #

Phone Tablet Desktop
Bottom navigation bar Navigation rail Permanent drawer (permanentDrawer: true)

Install #

dependencies:
  adaptive_scaffold_router: ^0.1.0

Quick start — with go_router #

Wrap your StatefulShellRoute branches in an AdaptiveNavigationShell:

import 'package:adaptive_scaffold_router/adaptive_scaffold_router.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

final GoRouter router = GoRouter(
  initialLocation: '/inbox',
  routes: <RouteBase>[
    StatefulShellRoute.indexedStack(
      builder: (BuildContext context, GoRouterState state,
              StatefulNavigationShell navigationShell) =>
          AdaptiveNavigationShell(
        navigationShell: navigationShell,
        destinations: const <NavigationDestination>[
          NavigationDestination(icon: Icon(Icons.inbox), label: 'Inbox'),
          NavigationDestination(icon: Icon(Icons.article), label: 'Articles'),
          NavigationDestination(icon: Icon(Icons.settings), label: 'Settings'),
        ],
      ),
      branches: <StatefulShellBranch>[
        StatefulShellBranch(routes: <RouteBase>[
          GoRoute(path: '/inbox', builder: (_, __) => const InboxPage()),
        ]),
        StatefulShellBranch(routes: <RouteBase>[
          GoRoute(path: '/articles', builder: (_, __) => const ArticlesPage()),
        ]),
        StatefulShellBranch(routes: <RouteBase>[
          GoRoute(path: '/settings', builder: (_, __) => const SettingsPage()),
        ]),
      ],
    ),
  ],
);

class App extends StatelessWidget {
  const App({super.key});
  @override
  Widget build(BuildContext context) =>
      MaterialApp.router(routerConfig: router);
}

The number of destinations matches the number of StatefulShellBranches. Resize the window from phone to desktop width and watch the navigation morph — while each tab keeps exactly where you left it.

Without go_router #

AdaptiveScaffold works standalone, exactly like the original:

AdaptiveScaffold(
  selectedIndex: _index,
  onSelectedIndexChange: (int i) => setState(() => _index = i),
  destinations: const <NavigationDestination>[
    NavigationDestination(icon: Icon(Icons.inbox), label: 'Inbox'),
    NavigationDestination(icon: Icon(Icons.article), label: 'Articles'),
  ],
  body: (_) => MyBody(index: _index),
  // Optional per-breakpoint bodies:
  smallBody: (_) => MyCompactBody(index: _index),
  secondaryBody: (_) => MyDetailPane(),
)

Customizing the navigation #

Badges — compose a Material Badge into any destination's icon; it shows in both the bottom bar and the rail:

NavigationDestination(
  icon: Badge(label: Text('3'), child: Icon(Icons.inbox)),
  label: 'Inbox',
)

Rail header / footerleadingExtendedNavRail (or leadingUnextendedNavRail) adds a header above the destinations; trailingNavRail adds a footer below them (shown on the rail at tablet/desktop widths):

AdaptiveNavigationShell(
  navigationShell: navigationShell,
  leadingExtendedNavRail: const Text('MAIL'),
  trailingNavRail: const Icon(Icons.logout),
  destinations: destinations,
)

Permanent desktop drawer — set permanentDrawer: true to render a persistent NavigationDrawer instead of the extended rail at the large and extra-large breakpoints. The rail still shows at medium/medium-large widths, and branch state is preserved when resizing between the two:

AdaptiveNavigationShell(
  navigationShell: navigationShell,
  permanentDrawer: true,
  destinations: destinations,
)

Cupertino / platform-adaptive bottom bar — supply a bottomNavigationBuilder to swap the small-breakpoint bar (e.g. a CupertinoTabBar on Apple platforms), or set cupertino: true to always use one:

AdaptiveNavigationShell(
  navigationShell: navigationShell,
  destinations: destinations,
  bottomNavigationBuilder: (context, destinations, index, onSelected) {
    final TargetPlatform platform = Theme.of(context).platform;
    final bool apple = platform == TargetPlatform.iOS ||
        platform == TargetPlatform.macOS;
    return apple
        ? AdaptiveScaffold.cupertinoTabBar(
            destinations: destinations, currentIndex: index, onTap: onSelected)
        : AdaptiveScaffold.standardBottomNavigationBar(
            destinations: destinations, currentIndex: index,
            onDestinationSelected: onSelected);
  },
)

Migrating from flutter_adaptive_scaffold #

Change the dependency and the import:

- flutter_adaptive_scaffold: ^0.3.3
+ adaptive_scaffold_router: ^0.1.0
- import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
+ import 'package:adaptive_scaffold_router/adaptive_scaffold_router.dart';

AdaptiveScaffold, AdaptiveLayout, SlotLayout, Breakpoint and Breakpoints keep the same API. To also fix go_router state loss, move your navigation into an AdaptiveNavigationShell (see above).

How state preservation works #

Two things combine:

  1. go_router lays branches out in an IndexedStack (StatefulShellRoute.indexedStack), so each branch's Navigator stays mounted while you switch tabs.
  2. adaptive_scaffold_router feeds that single navigationShell widget into the scaffold body under one stable key for every breakpoint. Changing the breakpoint therefore only swaps the navigation chrome — the body subtree is never torn down.

The original assigned a different body slot/key per breakpoint, so resizing rebuilt the body and dropped its state. This package doesn't.

Breakpoints #

Material 3 breakpoints are provided out of the box and can be overridden:

Breakpoint Width (dp) Typical chrome
small 0–600 Bottom navigation bar
medium 600–840 Navigation rail
mediumLarge 840–1200 Extended rail
large 1200–1600 Extended rail
extraLarge 1600+ Extended rail
AdaptiveNavigationShell(
  navigationShell: navigationShell,
  destinations: destinations,
  smallBreakpoint: const Breakpoint.small(),
  mediumBreakpoint: Breakpoints.medium,
  // ...custom Breakpoints supported
)

Roadmap #

  • Cupertino-styled rail/sidebar for Apple desktop (the bottom bar is already Cupertino-capable via bottomNavigationBuilder / cupertino).
  • Richer per-destination customization (label visibility, icon transitions).

🤝 Contributing #

Contributions are welcome! Please feel free to open an issue or submit a Pull Request.

📄 License #

This project is licensed under the BSD 3-Clause License — see the LICENSE file for details. It is derived from flutter_adaptive_scaffold by The Flutter Authors, used under the same license.

👨‍💻 Author #

Created with ❤️ by Akhilesh · igloodev

🙏 Acknowledgments #

📚 Additional Resources #


If you find this package useful, please give it a ⭐ on GitHub and a 👍 on pub.dev!

2
likes
160
points
248
downloads
screenshot

Documentation

API reference

Publisher

verified publisherigloodev.in

Weekly Downloads

Adaptive navigation scaffold for Material 3 — drop-in successor to flutter_adaptive_scaffold with first-class go_router support and state preservation.

Repository (GitHub)
View/report issues

Topics

#adaptive #responsive #navigation #material #go-router

License

BSD-3-Clause (license)

Dependencies

flutter, go_router

More

Packages that depend on adaptive_scaffold_router