staggered_menu_flutter
A premium staggered slide-in navigation menu for Flutter.
Animated pre-layers ยท Backdrop blur glass panel ยท Hover effects ยท Fully themeable.
โจ Features
| Feature | Details |
|---|---|
| ๐ Staggered layers | Multiple coloured sheets slide in behind the glass panel, each offset in time |
| ๐ซ Backdrop blur panel | Frosted-glass panel with configurable blur sigma and tint opacity |
| ๐ฑ Hover effects | Item and social-link hover states (colour + opacity) โ perfect for web & desktop |
| ๐ข Item numbering | Optional two-digit ordinals that fade in with each menu item |
| ๐จ Deep theming | Every colour, font, spacing, and motion curve is configurable via StaggeredMenuThemeData |
| ๐ฑ Responsive | Full-width panel on mobile, clamped fractional width on larger screens |
| โฟ Accessible | Semantics labels on all interactive elements |
| ๐ Left / right | Panel can slide in from either edge |
| ๐ฌ Socials section | Optional footer row with hover-dimming spotlight effect |
| ๐ฎ Controller | StaggeredMenuController for programmatic open / close / toggle |
| ๐จ Inherited theme | StaggeredMenuTheme InheritedWidget โ set once, inherit everywhere |
| ๐ค Route helper | StaggeredRouteHelper.fromRoutes() maps named routes to menu items automatically |
| ๐งฉ Custom item builder | itemBuilder slot for fully custom per-item rendering while keeping stagger animation |
| โจ๏ธ Keyboard nav | Focus trap when open โ Escape closes the menu |
๐ Getting started
Add to your pubspec.yaml:
dependencies:
staggered_menu_flutter: ^0.0.3
Then run:
flutter pub get
๐จ Usage
Minimal
import 'package:staggered_menu_flutter/staggered_menu_flutter.dart';
StaggeredMenu(
items: [
StaggeredMenuItem(label: 'Home', onTap: () {}),
StaggeredMenuItem(label: 'About', onTap: () {}),
StaggeredMenuItem(label: 'Contact', onTap: () {}),
],
child: Scaffold(
body: Center(child: Text('My App')),
),
)
With all options
StaggeredMenu(
position: MenuPosition.right, // or MenuPosition.left
theme: StaggeredMenuThemeData(
accentColor: Color(0xFFFF2D55),
preLayerColors: [Color(0xFFFFC2D1), Color(0xFFFF2D55)],
panelColor: Colors.white,
panelOpacity: 0.93,
blurSigma: 16,
barrierColor: Color(0x44000000),
showItemNumbering: true,
enableHoverEffects: true,
duration: Duration(milliseconds: 800),
panelCurve: Curves.easeOutQuart,
),
logo: Text(
'STUDIO',
style: TextStyle(color: Colors.white, fontWeight: FontWeight.w800),
),
items: [
StaggeredMenuItem(label: 'Home', onTap: () {}),
StaggeredMenuItem(label: 'Work', onTap: () {}),
StaggeredMenuItem(label: 'About', onTap: () {}),
StaggeredMenuItem(label: 'Contact', onTap: () {}),
],
socialItems: [
StaggeredSocialItem(label: 'GitHub', onTap: () {}),
StaggeredSocialItem(label: 'Dribbble', onTap: () {}),
StaggeredSocialItem(label: 'X', onTap: () {}),
],
onMenuOpen: () => print('opened'),
onMenuClose: () => print('closed'),
child: Scaffold(
backgroundColor: Color(0xFF0E0E12),
body: Center(child: Text('Hello')),
),
)
๏ฟฝ Controller
Open, close, or toggle the menu from code:
final controller = StaggeredMenuController();
StaggeredMenu(
controller: controller,
items: [ /* โฆ */ ],
child: myScaffold,
);
// Later:
controller.open();
controller.close();
controller.toggle();
// Dispose when done:
controller.dispose();
๐จ Inherited theme
Wrap a subtree with StaggeredMenuTheme to avoid passing theme: to every menu:
StaggeredMenuTheme(
data: StaggeredMenuThemeData(accentColor: Colors.red),
child: MaterialApp(home: MyPage()),
)
Resolution order: explicit theme parameter โ nearest StaggeredMenuTheme โ built-in defaults.
๐ค Named routes integration
StaggeredMenu(
items: StaggeredRouteHelper.fromRoutes(
context,
routes: {
'/': 'Home',
'/about': 'About',
'/contact': 'Contact',
},
currentRoute: ModalRoute.of(context)?.settings.name,
),
child: myScaffold,
)
The active route automatically gets a null onTap (disabled).
๐งฉ Custom item builder
Replace the default uppercase-label rendering while keeping the stagger animation:
StaggeredMenu(
itemBuilder: (context, item, index, hovered) {
return Text(
item.label,
style: TextStyle(color: hovered ? Colors.red : Colors.white),
);
},
items: [ /* โฆ */ ],
child: myScaffold,
)
โจ๏ธ Keyboard navigation
When the menu overlay is open:
- A
FocusScopetraps focus within the panel. - Pressing Escape closes the menu.
No extra setup required โ it works out of the box.
๏ฟฝ๐จ Theming reference
All properties have sensible defaults โ override only what you need using copyWith:
const StaggeredMenuThemeData().copyWith(
accentColor: Colors.deepPurple,
blurSigma: 20,
duration: Duration(milliseconds: 600),
)
Full property list
| Property | Type | Default | Description |
|---|---|---|---|
preLayerColors |
List<Color> |
purple tones | Decorative layers behind the panel |
panelColor |
Color |
white |
Panel base fill colour |
panelOpacity |
double |
0.95 |
Panel fill alpha (0โ1) |
blurSigma |
double |
12 |
Backdrop blur std-dev |
accentColor |
Color |
#5227FF |
Numbers, hover, social title |
toggleColorClosed |
Color |
white |
Toggle icon colour when closed |
toggleColorOpen |
Color |
black |
Toggle icon colour when open |
toggleIconSize |
double |
22 |
Size of the + icon |
toggleRotationDegrees |
double |
225 |
Rotation of the + on open |
headerPadding |
EdgeInsets |
h24 v20 |
Padding around logo + toggle row |
panelPadding |
EdgeInsets |
custom | Inner panel padding |
panelMinWidth |
double |
260 |
Minimum panel width (px) |
panelMaxWidth |
double |
420 |
Maximum panel width (px) |
panelWidthFraction |
double |
0.38 |
Panel width as screen fraction |
mobileBreakpoint |
double |
640 |
Full-width panel below this width |
closeOnClickAway |
bool |
true |
Close when tapping the barrier |
barrierColor |
Color |
transparent | Scrim behind the panel |
itemTextStyle |
TextStyle |
bold 48px | Menu item text |
itemHoverTextStyle |
TextStyle |
bold 48px accent | Menu item hover text |
numberTextStyle |
TextStyle |
bold 13px accent | Ordinal numbers |
socialsTitleStyle |
TextStyle |
semi 14px | "Socials" heading |
socialLinkStyle |
TextStyle |
semi 16px | Social link text |
socialLinkHoverStyle |
TextStyle |
semi 16px accent | Social link hover |
showItemNumbering |
bool |
true |
Show two-digit ordinals |
enableHoverEffects |
bool |
true |
Enable mouse-over interactions |
duration |
Duration |
900 ms |
Total open/close duration |
panelCurve |
Curve |
easeOutQuart |
Panel slide curve |
layerCurve |
Curve |
easeOutQuart |
Pre-layer slide curve |
itemCurve |
Curve |
easeOutQuart |
Item entrance curve |
layerStagger |
double |
0.08 |
Normalised delay between layers |
itemStagger |
double |
0.07 |
Normalised delay between items |
๐ Package structure
staggered_menu_flutter/
โโโ lib/
โ โโโ staggered_menu_flutter.dart โ public barrel (import this)
โ โโโ src/
โ โโโ controller.dart โ StaggeredMenuController
โ โโโ menu_theme.dart โ StaggeredMenuTheme (InheritedWidget)
โ โโโ models.dart โ StaggeredMenuItem, StaggeredSocialItem, MenuPosition
โ โโโ route_helper.dart โ StaggeredRouteHelper
โ โโโ theme.dart โ StaggeredMenuThemeData
โ โโโ staggered_menu.dart โ StaggeredMenu widget + itemBuilder + keyboard nav
โโโ example/
โ โโโ lib/main.dart โ runnable demo
โโโ test/
โ โโโ staggered_menu_flutter_test.dart (33 tests)
โโโ CHANGELOG.md
โโโ LICENSE
โโโ pubspec.yaml
๐งช Running tests
flutter test
๐บ Roadmap
xStaggeredMenuControllerfor programmatic open/closexNamed routes integration helper (StaggeredRouteHelper)xStaggeredMenuThemeinherited widgetxCustom item builder slot (itemBuilder)xKeyboard navigation (focus trap + Escape)
Upcoming:
RTL layout supportSpring physics animation presetBuilt-in hero transition for page changes
๐ค Contributing
PRs and issues are welcome at github.com/NexivaServices/staggered_menu_flutter!
Please open an issue before submitting a large change so we can discuss the approach.
- Fork the repository
- Create your feature branch (
git checkout -b feat/my-feature) - Commit your changes (
git commit -m 'feat: add my feature') - Push to the branch (
git push origin feat/my-feature) - Open a Pull Request
๐ License
MIT ยฉ 2026 โ see LICENSE for details.
Libraries
- A staggered sliding navigation menu for Flutter.