NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev
Adaptive master-detail layout for Flutter — automatically switches between compact and two-pane layouts across mobile, tablet, and desktop.
Last release 6 months ago
29 Mar 2026
Too new to tell
only 2 release windows
Most releases are documented
notes for 3 of 5 stable releases
Nothing withdrawn
no release was ever pulled
6 months old
5 releases · first in 2026
One column per month.
> All changes are additive and backward compatible.
All changes are additive and backward compatible. Existing
AdaptiveDestination(icon: Icons.people, label: '...')code compiles and runs with zero changes.
AdaptiveShellTheme — full navigation theming 🎨A single const-able class that controls every visual aspect of the
navigation chrome. Pass it to AdaptiveShell.theme:
AdaptiveShell(
theme: const AdaptiveShellTheme(
// Rail
railMinExtendedWidth: 180, // tighter default (was Flutter's 256)
railBackgroundColor: Color(0xFFF8F9FA),
railIndicatorColor: Color(0xFFD0BCFF),
railSelectedLabelStyle: TextStyle(fontWeight: FontWeight.bold),
railDecoration: BoxDecoration(
border: Border(right: BorderSide(color: Color(0xFFE0E0E0))),
),
// Nav bar
navBarIndicatorColor: Color(0xFFD0BCFF),
navBarLabelBehavior: NavigationDestinationLabelBehavior.alwaysShow,
navBarHeight: 72,
),
)
Supports copyWith and lerp.
AdaptiveShellController — programmatic rail control 🎛️Collapse/expand the navigation rail from anywhere without prop-drilling:
final _nav = AdaptiveShellController();
AdaptiveShell(controller: _nav, ...)
// From an AppBar action or FAB:
IconButton(onPressed: _nav.toggleRail, icon: const Icon(Icons.menu))
Methods: collapseRail(), expandRail(), toggleRail().
Property: isRailCollapsed.
AdaptiveDestination — SVG, PNG, custom 🖼️icon is now optional (IconData?). Use iconWidget, selectedIconWidget,
or iconBuilder for full widget-based icons:
// Classic IconData — unchanged, still works
const AdaptiveDestination(icon: Icons.home, label: 'Home')
// SVG / PNG widget pair
AdaptiveDestination(
iconWidget: SvgPicture.asset('assets/home.svg'),
selectedIconWidget: SvgPicture.asset('assets/home_filled.svg'),
label: 'Home',
)
// Builder — recommended for theme-driven SVG colors
AdaptiveDestination(
iconBuilder: (context, isSelected) => SvgPicture.asset(
'assets/home.svg',
colorFilter: ColorFilter.mode(
isSelected
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.onSurfaceVariant,
BlendMode.srcIn,
),
),
label: 'Home',
)
Replace the entire NavigationBar or NavigationRail with your own widget:
AdaptiveShell(
navigationBarBuilder: (context, destinations, index, onSelected) =>
MyCustomBottomBar(...),
navigationRailBuilder: (context, destinations, index, onSelected, isExtended) =>
MyCustomSidebar(...),
)
AdaptiveDestination fields| Field | Description |
|---|---|
iconSize: double? |
Wraps the resolved icon in a SizedBox for consistent SVG/PNG sizing |
tooltip: String? |
Custom tooltip (defaults to label) |
enabled: bool |
Disable individual destinations (grayed out, non-tappable) |
badgeLabel: String? |
Flexible badge: "" = dot, "NEW", "99+" |
minExtendedWidth: 160
(previously fell back to Flutter's built-in 256 default, which consumed
too much horizontal space on typical laptop windows).Full Changelog : v1.0.0...v1.1.0
Full Changelog: v1.0.0...v1.1.0
A standalone responsive builder widget that works without an AdaptiveShell ancestor — it uses LayoutBuilder and AdaptiveBreakpoints directly:
AdaptiveBuilder(
compact: (context) => MobileWidget(),
medium: (context) => TabletWidget(), // optional, falls back to compact
expanded: (context) => DesktopWidget(), // optional, falls back to medium
breakpoints: AdaptiveBreakpoints.tabletFirst, // customisable
)
Map any ShortcutActivator (e.g. SingleActivator, LogicalKeySet) to a navigation destination index. Only active on medium/expanded layouts (tablet / desktop):
AdaptiveShell(
keyboardShortcuts: {
SingleActivator(LogicalKeyboardKey.digit1, control: true): 0,
SingleActivator(LogicalKeyboardKey.digit2, control: true): 1,
},
// ...
)
A chevron toggle button above the rail destinations lets users collapse the rail to icon-only mode. railCollapseOnMedium auto-collapses when the layout enters medium mode:
AdaptiveShell(
railCollapsible: true, // shows toggle button
railCollapseOnMedium: true, // auto-collapses on tablet breakpoint
// ...
)
Replace the hardcoded VerticalDivider between the master and detail panes with any widget:
AdaptiveShell(
paneDivider: VerticalDivider(width: 2, color: Colors.blue),
// ...
)
Quick access to layout information anywhere in your widget tree:
context.screenType / context.layoutMode — get current LayoutMode (usable in switch)context.isCompact, context.isMedium, context.isExpanded — boolean checkscontext.isMobile, context.isTablet, context.isDesktop — semantic aliasescontext.isTwoPane — true when two panes are visiblecontext.adaptiveWidth(base) / context.adaptiveHeight(base) — scale dimensionscontext.adaptivePadding() — responsive EdgeInsets (16 / 24 / 32)context.adaptiveFontSize(base) / context.adaptiveSpacing(base) — scale text & gapscontext.adaptiveColumns — grid column count: 1 / 2 / 3 (compact / medium / expanded)context.adaptiveValue<T>(compact:, medium:, expanded:) — any typed value per breakpoint// Boolean checks
if (context.isCompact) { /* mobile */ }
if (context.isTablet) { /* medium or expanded */ }
// Typed per-breakpoint value
final padding = context.adaptiveValue(compact: 8.0, medium: 16.0, expanded: 24.0);
// Grid columns
GridView.count(crossAxisCount: context.adaptiveColumns, ...)
// Layout mode in switch
switch (context.layoutMode) {
case LayoutMode.compact: return MobileNav();
case LayoutMode.medium: return TabletNav();
case LayoutMode.expanded: return DesktopNav();
}
React to layout mode transitions for analytics or state management:
AdaptiveShell(
onLayoutModeChanged: (oldMode, newMode) {
print('Layout: $oldMode → $newMode');
},
// ...
)
Visual indicator showing current layout mode and breakpoints during development:
AdaptiveShell(
debugShowLayoutMode: true, // Shows overlay in top-right corner
// ...
)
Proportionally scales your layout to fill any screen size — the same technique that made responsive_framework's AutoScale popular:
AdaptiveShell(
autoScale: true, // render at 360 dp design canvas, scale to screen
scaleFactor: 1.2, // optional: 20% boost on top of auto scale
autoScaleDesignWidth: 390, // optional: override canvas (e.g. iPhone 14 = 390 dp)
// ...
)
Default autoScaleDesignWidth is 360 dp — a typical phone canvas that ensures a compact (single-pane, bottom-nav) layout by default. The debug overlay gains a live ⚖️ Scale ×N.NN line when autoScale is enabled.
Preserves scroll positions and widget state when the device rotates, the window resizes, or the layout mode changes:
AdaptiveShell(
persistState: true,
stateKey: 'my_shell', // optional namespace (default: 'adaptive_shell')
// ...
)
Uses stable GlobalKeys on child1/child2 so element subtrees survive compact ↔ wide transitions, plus a keyed PageStorage bucket for scroll restoration.
Fine-tune detail-pane animations:
AdaptiveShell(
transitionCurve: Curves.easeInOutCubic, // custom curve (default: easeInOut)
enableHeroAnimations: true, // slide + fade instead of cross-fade
// ...
)
AdaptiveMasterDetailautoScale, scaleFactor, autoScaleDesignWidth, persistState, stateKey, transitionCurve, enableHeroAnimations, paneDivider, railCollapsible, railCollapseOnMedium, keyboardShortcuts are all forwarded to the internal AdaptiveShell.
AdaptiveShell refactored from StatelessWidget to StatefulWidget — fully backward-compatible.onLayoutModeChanged now reliably fires across hot-reload and test pumps.AdaptiveMasterDetail._computeMode respects autoScale — navigation decisions (push vs in-place) now correctly match the visually rendered compact layout.NavigationRail overflow when railCollapsible: true — the toggle button (~36 px) consumed height from the Column that also holds the NavigationRail, causing a RenderFlex overflowed by N pixels on the bottom assertion on short screens with many destinations. The rail is now wrapped in LayoutBuilder → SingleChildScrollView + ConstrainedBox(minHeight) + IntrinsicHeight so destinations scroll gracefully when they exceed the available height, while still centering correctly on taller screens. The wrapper is applied only when the toggle is present; the default (railCollapsible: false) path is unchanged.AdaptiveMasterDetail pass-through.paneDivider.railCollapsible overflow fix (expanded + medium layouts, and default path).1.0.x code compiles and runs unchanged.BuildContext extensions (layoutMode, adaptiveColumns, adaptiveValue, and all v1.1.0 additions) may conflict if you already define identically-named extensions. Resolve with a hide import: import 'package:adaptive_shell/adaptive_shell.dart' hide AdaptiveContextExtensions;Nothing published for this version
Nothing published for this version
Full Changelog : https://github.com/RakeshGowdaR/adaptive_shell/commits/v1.0.0
Full Changelog: https://github.com/RakeshGowdaR/adaptive_shell/commits/v1.0.0
AdaptiveShell — flexible wrapper with child1/child2 for full manual control over both panes, navigation, and state.AdaptiveMasterDetail<T> — zero-boilerplate generic widget with itemBuilder/detailBuilder. Handles selection state, navigation (push on mobile, side-pane on tablet), and responsive layout switching automatically.NavigationBar (compact) / NavigationRail (medium/expanded) switching.AdaptiveShell.of(context) for descendant layout-mode awareness.AdaptiveShell.isTwoPane(context) convenience helper.AdaptiveBreakpoints with Material 3 window size class defaults + tabletFirst preset.AdaptiveDestination with badge support.emptyDetailPlaceholder for large screens with no selection.masterHeader and masterBuilder for custom master pane layouts.compactDetailScaffoldBuilder for custom mobile detail screen wrapping.Your coding agent can read these notes before it upgrades. Set up the MCP server →