NovaDrawer
A modern, production-grade, and highly responsive app drawer system for Flutter.
Supports mobile, tablet, and desktop with 16+ animation types, 10 header variants,
10 surface styles, nested menus, RTL, accessibility, slot-based builders, and much more.
๐ Table of Contents
- Features
- Installation
- Quick Start
- Complete Example
- Header System
- Surface Styles
- Animations
- Content Widgets
- Controller API
- Responsive Behavior
- Theming
- Slot-Based Builder APIs
- Background Effects
- Gesture Controls
- Mini-Drawer Mode
- Dynamic Data Loading
- RTL Support
- Accessibility
- Package Structure
- API Reference
- Migration Guide
โจ Features
Core
- Fully responsive layout that adapts seamlessly across mobile, tablet, and desktop
- LTR and RTL language support
- Expandable and collapsible sections with smooth transitions
- Nested menu items with animated expansion (multi-level)
- Dynamic width adjustment depending on screen size
๐จ Header System (10 variants)
| Variant | Description |
|---|---|
classic |
Standard cover + avatar + user info layout |
glassmorphism |
Frosted glass effect with blur and transparency |
compact |
Minimal single-row layout for space-constrained UIs |
hero |
Large cover image, magazine-style dramatic layout |
expanded |
Full detail with expand/collapse animation |
animatedGradient |
Cycling gradient background header |
avatarStack |
Multiple account avatars overlapping |
multiAction |
Prominent action buttons row |
statusAware |
Status-focused with breathing animation |
collapsible |
Toggle between expanded/collapsed states |
Each header supports: avatar, cover image, user name, role, email, status indicator, action buttons, notification badge, edit profile shortcut, RTL, theme awareness, loading skeleton state, and custom widget slots.
๐๏ธ Surface Styles (10 variants)
| Style | Description |
|---|---|
plain |
Flat background color |
elevated |
Shadow-lifted surface |
glassmorphism |
Frosted glass with backdrop blur |
blurred |
Background-blurred surface |
gradient |
Linear gradient fill |
premiumShadow |
Deep multi-layer shadow |
outlinedMinimal |
Subtle border outline |
neumorphic |
Soft inset/outset shadows |
imageBacked |
Background image surface |
animatedMeshGradient |
Animated shifting gradient |
๐ฆ Content Widgets
- NovaDrawerStatsCard โ Row of stat items with dividers
- NovaDrawerShortcutsGrid โ Tappable shortcut grid with badges
- NovaDrawerRecentItems โ Recent items list with timestamps
- NovaDrawerFilterChipsWidget โ Horizontally scrollable filter chips
- NovaDrawerAppStatusWidget โ Connection status and version info
- NovaDrawerWorkspaceSwitcher โ Expandable workspace/account switcher
๐ฌ Animations (16+ types)
| Animation | Description |
|---|---|
slide |
Slides in from the edge |
fade |
Opacity fade in/out |
scale |
Scales up from a point |
rotate |
3D perspective rotation |
morph |
Shape morphing transition |
elastic |
Bouncy overshoot effect |
spring |
Physics-based spring motion |
shimmer |
Loading/highlight sweep |
blur |
Gaussian blur transition |
gradient |
Color gradient transition |
floating |
Floating overlay with shadow depth |
floatingBounce |
Floating entry with bounce settle |
floatingReveal |
Floating progressive reveal |
wave |
Wave distortion transition |
parallax |
Parallax depth layers |
curtain |
Theatrical curtain open/close |
All animations are smooth and performant. Developers can customize duration, curve, and style.
๐ง Customizability
- Themeable colors, text styles, icons, shadows, and borders
- Slot-based builder APIs for every component (header, items, sections, backgrounds, footer, etc.)
- Inject custom widgets inside drawer sections
- Gesture controls (swipe to open/close)
- Pin drawer open on desktop/tablet
- Light and dark theme support
๐ Advanced Features
- Dynamic data loading (menu items fetched from API)
- Active route highlighting
- Built-in accessibility support (screen readers, focus order, scalable fonts)
- Mini-drawer mode for tablet/desktop
- Custom backgrounds (animated gradient, particle effects)
- Auto-hide on scroll support
- Account switcher support
- Loading skeletons for headers and content
๐ฆ Installation
Add to your pubspec.yaml:
dependencies:
nova_drawer:
git:
url: https://github.com/yasersabri580-oss/NovaDrawer.git
Then run:
flutter pub get
๐ Quick Start
The fastest way to add a drawer to your app:
1. Import the package
// The barrel export lives at lib/main.dart
import 'package:nova_drawer/main.dart';
2. Create a controller
final _controller = NovaDrawerController(
initialSelectedItemId: 'home',
);
3. Build the scaffold
NovaDrawerScaffold(
controller: _controller,
appBar: AppBar(
title: const Text('My App'),
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: _controller.toggle,
),
),
drawer: NovaAppDrawer(
controller: _controller,
sections: [
NovaDrawerSectionData(
id: 'main',
title: 'Navigation',
items: [
NovaDrawerItem(
id: 'home',
title: 'Home',
icon: Icons.home_outlined,
selectedIcon: Icons.home,
route: '/home',
),
NovaDrawerItem(
id: 'profile',
title: 'Profile',
icon: Icons.person_outline,
selectedIcon: Icons.person,
badge: NovaDrawerItemBadge(count: 2),
),
],
),
],
header: NovaDrawerHeader(
config: NovaHeaderConfig(
variant: NovaHeaderVariant.classic,
profile: NovaHeaderUserProfile(
name: 'Jane Developer',
email: 'jane@example.com',
status: NovaUserStatus.online,
),
),
),
onItemTap: (item) {
Navigator.pushNamed(context, item.route ?? '/');
},
),
body: const Center(child: Text('Hello, NovaDrawer!')),
)
๐ฅ Complete Example
The following is a full, self-contained Flutter app that showcases the most important NovaDrawer features:
import 'package:flutter/material.dart';
import 'package:nova_drawer/main.dart'; // barrel export at lib/main.dart
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'NovaDrawer Demo',
theme: ThemeData(colorSchemeSeed: Colors.indigo, useMaterial3: true),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
// โโ 1. Create controller โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
final _controller = NovaDrawerController(
initialSelectedItemId: 'home',
);
String _currentPage = 'Home';
// โโ 2. Define sections with nested items and badges โโโโโโโโโโโโโโโโโโโ
late final _sections = [
NovaDrawerSectionData(
id: 'main',
title: 'Main',
items: [
NovaDrawerItem(
id: 'home',
title: 'Home',
icon: Icons.home_outlined,
selectedIcon: Icons.home,
route: '/home',
onTap: () => setState(() => _currentPage = 'Home'),
),
NovaDrawerItem(
id: 'dashboard',
title: 'Dashboard',
icon: Icons.dashboard_outlined,
selectedIcon: Icons.dashboard,
badge: const NovaDrawerItemBadge(count: 3),
onTap: () => setState(() => _currentPage = 'Dashboard'),
),
NovaDrawerItem(
id: 'messages',
title: 'Messages',
icon: Icons.chat_bubble_outline,
selectedIcon: Icons.chat_bubble,
badge: const NovaDrawerItemBadge(label: 'NEW'),
onTap: () => setState(() => _currentPage = 'Messages'),
),
],
),
NovaDrawerSectionData(
id: 'workspace',
title: 'Workspace',
items: [
// Nested menu with sub-items
NovaDrawerItem(
id: 'projects',
title: 'Projects',
icon: Icons.folder_outlined,
selectedIcon: Icons.folder,
initiallyExpanded: true,
children: [
NovaDrawerItem(
id: 'active',
title: 'Active',
icon: Icons.circle,
onTap: () => setState(() => _currentPage = 'Active Projects'),
),
NovaDrawerItem(
id: 'archived',
title: 'Archived',
icon: Icons.archive_outlined,
onTap: () => setState(() => _currentPage = 'Archived'),
),
],
),
NovaDrawerItem(
id: 'team',
title: 'Team',
icon: Icons.group_outlined,
selectedIcon: Icons.group,
onTap: () => setState(() => _currentPage = 'Team'),
),
],
),
NovaDrawerSectionData(
id: 'account',
title: 'Account',
items: [
NovaDrawerItem(
id: 'settings',
title: 'Settings',
icon: Icons.settings_outlined,
selectedIcon: Icons.settings,
onTap: () => setState(() => _currentPage = 'Settings'),
),
NovaDrawerItem(
id: 'logout',
title: 'Sign Out',
icon: Icons.logout,
isEnabled: true,
onTap: () => _showLogoutDialog(context),
),
],
),
];
void _showLogoutDialog(BuildContext context) {
showDialog(
context: context,
builder: (_) => AlertDialog(
title: const Text('Sign Out'),
content: const Text('Are you sure you want to sign out?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Sign Out'),
),
],
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// โโ 3. Build with NovaDrawerScaffold โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
return NovaDrawerScaffold(
controller: _controller,
// App bar with hamburger menu
appBar: AppBar(
title: Text(_currentPage),
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: _controller.toggle,
),
),
// โโ 4. Configure the drawer โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
drawer: NovaAppDrawer(
controller: _controller,
sections: _sections,
// โโ 5. Hero-style header with user profile โโโโโโโโโโโโโโโโโโโ
header: NovaDrawerHeader(
config: NovaHeaderConfig(
variant: NovaHeaderVariant.hero,
profile: const NovaHeaderUserProfile(
name: 'Jane Developer',
email: 'jane@acme.io',
role: 'Senior Engineer',
status: NovaUserStatus.online,
notificationCount: 5,
avatarUrl: 'https://i.pravatar.cc/150?img=47',
),
showCloseButton: true,
showPinButton: true,
showEditProfileButton: true,
actions: [
NovaHeaderAction(
id: 'notifications',
icon: Icons.notifications_outlined,
badge: 5,
tooltip: 'Notifications',
onTap: () {},
),
NovaHeaderAction(
id: 'settings',
icon: Icons.settings_outlined,
tooltip: 'Settings',
onTap: () {},
),
],
onProfileTap: () {},
onEditProfile: () {},
),
),
// โโ 6. Content widgets above and below the menu โโโโโโโโโโโโโโ
// (inject via section headerWidget / footerWidget or as items)
footer: Column(
children: [
// Stats bar
NovaDrawerStatsCard(
stats: const [
NovaDrawerStatItem(label: 'Projects', value: '12'),
NovaDrawerStatItem(label: 'Tasks', value: '48'),
NovaDrawerStatItem(label: 'Done', value: '89%'),
],
),
// App status
NovaDrawerAppStatusWidget(
status: const NovaDrawerAppStatus(
isOnline: true,
version: '2.4.1',
statusMessage: 'All systems operational',
),
),
],
),
// โโ 7. Animation โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
config: const NovaDrawerConfig(
animationType: NovaDrawerAnimationType.spring,
animationConfig: NovaDrawerAnimationConfig(
duration: Duration(milliseconds: 380),
),
displayMode: NovaDrawerDisplayMode.auto,
isPinnable: true,
gestureConfig: NovaDrawerGestureConfig(
enableSwipeToOpen: true,
enableSwipeToClose: true,
swipeEdgeWidth: 24.0,
),
accessibilityConfig: NovaDrawerAccessibilityConfig(
enableSemantics: true,
drawerLabel: 'Main navigation drawer',
),
),
// โโ 8. Surface style โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Pass the surface via the theme or use NovaDrawerSurface widget.
theme: const NovaDrawerTheme(
selectedItemColor: Color(0xFF6366F1),
selectedItemBackgroundColor: Color(0x1A6366F1),
itemBorderRadius: BorderRadius.all(Radius.circular(12)),
elevation: 6.0,
),
// โโ 9. Callback โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
onItemTap: (item) {
_controller.selectItem(item.id);
},
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.auto_awesome, size: 48, color: Colors.indigo),
const SizedBox(height: 16),
Text(
_currentPage,
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 8),
const Text('Swipe from the left edge to open the drawer'),
],
),
),
);
}
}
๐ญ Header System
Switching between header variants
All 10 variants share the same NovaHeaderConfig. Change a single parameter to switch styles:
// Classic โ avatar + name + subtitle
NovaHeaderConfig(variant: NovaHeaderVariant.classic, profile: profile)
// Glassmorphism โ frosted glass with blur overlay
NovaHeaderConfig(variant: NovaHeaderVariant.glassmorphism, profile: profile)
// Compact โ icon-only row, ideal for mini/side drawers
NovaHeaderConfig(variant: NovaHeaderVariant.compact, profile: profile)
// Hero โ large cover photo with magazine-style layout
NovaHeaderConfig(variant: NovaHeaderVariant.hero, profile: profile)
// Expanded โ shows additional details and extra actions
NovaHeaderConfig(variant: NovaHeaderVariant.expanded, profile: profile)
// Animated gradient โ cycling colour background
NovaHeaderConfig(
variant: NovaHeaderVariant.animatedGradient,
profile: profile,
gradientColors: [Colors.indigo, Colors.purple, Colors.pink],
)
// Avatar stack โ multi-account overlay avatars
NovaHeaderConfig(
variant: NovaHeaderVariant.avatarStack,
profile: primaryUser,
accounts: [
NovaHeaderUserProfile(name: 'Alice', status: NovaUserStatus.online),
NovaHeaderUserProfile(name: 'Bob', status: NovaUserStatus.busy),
NovaHeaderUserProfile(name: 'Carol', status: NovaUserStatus.away),
],
onSwitchAccount: () => showAccountPicker(context),
)
// Multi-action โ big action buttons row
NovaHeaderConfig(
variant: NovaHeaderVariant.multiAction,
profile: profile,
actions: [
NovaHeaderAction(id: 'edit', icon: Icons.edit, label: 'Edit', onTap: () {}),
NovaHeaderAction(id: 'share', icon: Icons.share, label: 'Share', onTap: () {}),
NovaHeaderAction(id: 'logout', icon: Icons.logout, label: 'Sign Out',
isDestructive: true, onTap: () {}),
],
)
// Status-aware โ breathing animation on online indicator
NovaHeaderConfig(
variant: NovaHeaderVariant.statusAware,
profile: profile.copyWith(status: NovaUserStatus.online),
)
// Collapsible โ toggles between full and mini header
NovaHeaderConfig(
variant: NovaHeaderVariant.collapsible,
profile: profile,
enableCollapseExpand: true,
isCollapsed: false,
)
Loading skeleton state
NovaHeaderConfig(
variant: NovaHeaderVariant.classic,
profile: myProfile,
isLoading: isLoadingUser, // Shows skeleton shimmer while true
)
Fully custom header
NovaHeaderConfig(
customHeaderBuilder: (context, config) {
return Container(
height: 180,
color: Colors.teal,
child: Center(
child: Text(
config.profile?.name ?? '',
style: const TextStyle(color: Colors.white, fontSize: 24),
),
),
);
},
)
๐๏ธ Surface Styles
NovaDrawerSurface wraps any child with one of the 10 built-in surface styles:
NovaDrawerSurface(
config: NovaDrawerSurfaceConfig(
style: NovaDrawerSurfaceStyle.glassmorphism,
blurSigma: 18.0,
opacity: 0.75,
borderRadius: BorderRadius.circular(20),
),
child: myContent,
)
Quick surface showcase:
// Glassmorphism
NovaDrawerSurfaceConfig(style: NovaDrawerSurfaceStyle.glassmorphism, blurSigma: 15)
// Deep premium shadow
NovaDrawerSurfaceConfig(style: NovaDrawerSurfaceStyle.premiumShadow, elevation: 16)
// Gradient fill
NovaDrawerSurfaceConfig(
style: NovaDrawerSurfaceStyle.gradient,
gradientColors: [Color(0xFF1E3A5F), Color(0xFF4A1942)],
)
// Neumorphic soft-UI
NovaDrawerSurfaceConfig(
style: NovaDrawerSurfaceStyle.neumorphic,
backgroundColor: Color(0xFFE0E5EC),
)
// Animated mesh gradient
NovaDrawerSurfaceConfig(
style: NovaDrawerSurfaceStyle.animatedMeshGradient,
meshColors: [Colors.blue, Colors.purple, Colors.pink, Colors.cyan],
)
// Image-backed
NovaDrawerSurfaceConfig(
style: NovaDrawerSurfaceStyle.imageBacked,
backgroundImage: AssetImage('assets/drawer_bg.jpg'),
backgroundImageFit: BoxFit.cover,
)
๐ฌ Animations
Choosing an animation type
NovaDrawerConfig(
animationType: NovaDrawerAnimationType.elastic, // 16 types available
animationConfig: NovaDrawerAnimationConfig(
duration: Duration(milliseconds: 420),
curve: Curves.easeOutBack,
),
)
Physics-based spring animation
NovaDrawerConfig(
animationType: NovaDrawerAnimationType.spring,
animationConfig: NovaDrawerAnimationConfig(
springDamping: 0.65,
springStiffness: 250.0,
),
)
Wave / Curtain / Parallax
// Wave distortion
NovaDrawerConfig(animationType: NovaDrawerAnimationType.wave)
// Theatrical curtain split
NovaDrawerConfig(animationType: NovaDrawerAnimationType.curtain)
// Multi-layer depth parallax
NovaDrawerConfig(animationType: NovaDrawerAnimationType.parallax)
๐ฆ Content Widgets
Stats card
NovaDrawerStatsCard(
stats: const [
NovaDrawerStatItem(label: 'Projects', value: '12', icon: Icons.folder),
NovaDrawerStatItem(label: 'Tasks', value: '48', icon: Icons.task_alt),
NovaDrawerStatItem(label: 'Messages', value: '7', icon: Icons.chat_bubble),
],
)
Shortcuts grid
NovaDrawerShortcutsGrid(
shortcuts: [
NovaDrawerShortcut(
id: 'new_doc',
label: 'New Doc',
icon: Icons.add_box_outlined,
color: Colors.blue,
onTap: () {},
),
NovaDrawerShortcut(
id: 'upload',
label: 'Upload',
icon: Icons.cloud_upload_outlined,
color: Colors.green,
badge: 2,
onTap: () {},
),
NovaDrawerShortcut(
id: 'calendar',
label: 'Calendar',
icon: Icons.calendar_today_outlined,
color: Colors.orange,
onTap: () {},
),
NovaDrawerShortcut(
id: 'analytics',
label: 'Analytics',
icon: Icons.bar_chart,
color: Colors.purple,
onTap: () {},
),
],
)
Recent items
NovaDrawerRecentItems(
items: [
NovaDrawerRecentItem(
id: 'r1',
title: 'Q3 Report.pdf',
subtitle: 'Edited 2h ago',
icon: Icons.picture_as_pdf,
timestamp: DateTime.now().subtract(const Duration(hours: 2)),
onTap: () {},
),
NovaDrawerRecentItem(
id: 'r2',
title: 'Sprint Planning',
subtitle: 'Meeting notes',
icon: Icons.description_outlined,
timestamp: DateTime.now().subtract(const Duration(days: 1)),
onTap: () {},
),
],
)
Filter chips
NovaDrawerFilterChipsWidget(
chips: [
NovaDrawerFilterChip(id: 'all', label: 'All', isSelected: true, onSelected: (_) {}),
NovaDrawerFilterChip(id: 'active', label: 'Active', onSelected: (_) {}),
NovaDrawerFilterChip(id: 'done', label: 'Done', onSelected: (_) {}),
],
)
Workspace switcher
NovaDrawerWorkspaceSwitcher(
workspaces: [
NovaDrawerWorkspace(
id: 'personal',
name: 'Personal',
icon: Icons.person,
isActive: true,
onSelect: () {},
),
NovaDrawerWorkspace(
id: 'acme',
name: 'Acme Corp',
icon: Icons.business,
onSelect: () {},
),
NovaDrawerWorkspace(
id: 'startup',
name: 'My Startup',
icon: Icons.rocket_launch,
onSelect: () {},
),
],
)
App status footer
NovaDrawerAppStatusWidget(
status: const NovaDrawerAppStatus(
isOnline: true,
version: '2.4.1',
buildNumber: '142',
statusMessage: 'Connected ยท Last sync 5 min ago',
),
)
๐๏ธ Controller API
NovaDrawerController is a ChangeNotifier. Use it directly or provide it via NovaDrawerControllerProvider.
final controller = NovaDrawerController(
initialSelectedItemId: 'home',
initiallyOpen: false,
initiallyPinned: false, // useful for desktop default
);
// Open / close
controller.open();
controller.close();
controller.toggle();
// Pin (tablet/desktop persistent mode)
controller.pin();
controller.unpin();
controller.togglePin();
// Mini mode (icon-only sidebar)
controller.toMini();
controller.fromMini();
controller.toggleMini();
// Item selection
controller.selectItem('settings');
controller.selectByRoute('/settings/account'); // auto-expands parents
controller.clearSelection();
// Section expand/collapse
controller.expandSection('workspace');
controller.collapseSection('workspace');
controller.toggleSection('workspace');
// Nested item expand/collapse
controller.expandItem('projects');
controller.collapseItem('projects');
// Visibility / enable
controller.disableItem('logout');
controller.enableItem('logout');
controller.hideItem('admin');
controller.showItem('admin');
// Read state
print(controller.isOpen);
print(controller.isPinned);
print(controller.isMini);
print(controller.selectedItemId);
print(controller.isLoading);
Accessing the controller from descendants
// Provide at the top:
NovaDrawerControllerProvider(
controller: _controller,
child: MyDrawerContent(),
)
// Read anywhere below:
final ctrl = NovaDrawerControllerProvider.of(context); // subscribes
final ctrl = NovaDrawerControllerProvider.read(context); // one-shot read
๐ฑ Responsive Behavior
| Device | Breakpoint | Default Mode |
|---|---|---|
| Mobile | < 600 px | Overlay (slides over content) |
| Tablet | 600โ1024 px | Push (pushes content aside) |
| Desktop | > 1024 px | Side (persistent alongside content) |
Custom breakpoints
NovaDrawerConfig(
breakpoints: const NovaDrawerBreakpoints(
mobile: 540,
tablet: 960,
),
)
Force a specific mode
NovaDrawerConfig(displayMode: NovaDrawerDisplayMode.side) // Always persistent
NovaDrawerConfig(displayMode: NovaDrawerDisplayMode.overlay) // Always overlay
NovaDrawerConfig(displayMode: NovaDrawerDisplayMode.push) // Always push
NovaDrawerConfig(displayMode: NovaDrawerDisplayMode.mini) // Always mini
๐จ Theming
Using the built-in theme
NovaAppDrawer(
theme: const NovaDrawerTheme(
backgroundColor: Color(0xFF1E1E2E),
selectedItemColor: Color(0xFF89B4FA),
selectedItemBackgroundColor: Color(0x2089B4FA),
unselectedItemColor: Color(0xFFCDD6F4),
headerBackgroundColor: Color(0xFF181825),
itemBorderRadius: BorderRadius.all(Radius.circular(10)),
itemTextStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
sectionTitleStyle: TextStyle(fontSize: 11, letterSpacing: 1.2),
elevation: 8.0,
iconSize: 22.0,
itemHeight: 48.0,
expandedDrawerWidth: 280.0,
miniDrawerWidth: 64.0,
),
)
๐ Slot-Based Builder APIs
Override any part of the drawer with custom widgets:
NovaAppDrawer(
controller: _controller,
sections: _sections,
builders: NovaDrawerBuilders(
// Replace the default item rendering
itemBuilder: (context, item, isSelected) {
return AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: BoxDecoration(
color: isSelected ? Colors.indigo.withOpacity(0.15) : Colors.transparent,
borderRadius: BorderRadius.circular(12),
),
child: ListTile(
leading: Icon(item.icon, color: isSelected ? Colors.indigo : null),
title: Text(item.title),
selected: isSelected,
),
);
},
// Custom section header
sectionBuilder: (context, section) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(
section.title?.toUpperCase() ?? '',
style: const TextStyle(
fontSize: 11,
fontWeight: FontWeight.w700,
letterSpacing: 1.5,
color: Colors.grey,
),
),
);
},
// Custom loading placeholder
loadingBuilder: (context) {
return const Center(
child: Padding(
padding: EdgeInsets.all(32),
child: CircularProgressIndicator(),
),
);
},
// Custom empty state
emptyStateBuilder: (context) {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.inbox, size: 48, color: Colors.grey),
SizedBox(height: 8),
Text('No menu items', style: TextStyle(color: Colors.grey)),
],
),
);
},
// Custom error state
errorBuilder: (context, message, onRetry) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, color: Colors.red),
Text(message ?? 'Error'),
if (onRetry != null)
TextButton(onPressed: onRetry, child: const Text('Retry')),
],
),
);
},
// Custom footer
footerBuilder: (context) {
return const Padding(
padding: EdgeInsets.all(16),
child: Text('v1.0.0 ยท NovaDrawer', style: TextStyle(color: Colors.grey)),
);
},
),
)
๐ Background Effects
Animated gradient background
NovaAppDrawer(
controller: _controller,
sections: _sections,
enableGradientBackground: true,
gradientColors: const [
Color(0xFF0F2027),
Color(0xFF203A43),
Color(0xFF2C5364),
],
)
Particle effects
NovaAppDrawer(
controller: _controller,
sections: _sections,
enableParticleBackground: true,
particleColor: Colors.white,
particleCount: 30,
)
๐ Gesture Controls
NovaDrawerConfig(
gestureConfig: const NovaDrawerGestureConfig(
enableSwipeToOpen: true, // Swipe from left edge to open
enableSwipeToClose: true, // Swipe drawer to close
swipeEdgeWidth: 24.0, // Detection edge width in logical px
swipeSensitivity: 0.5, // 0.0 = very sensitive, 1.0 = very resistant
enableDragHandle: true, // Show a visible drag handle
dragHandleColor: Colors.grey,
),
)
๐ Mini-Drawer Mode
On tablet/desktop the drawer can collapse to a slim icon-only sidebar:
NovaDrawerConfig(
showMiniOnCollapse: true,
enableHoverExpand: true, // Expand on mouse hover
hoverExpandDelay: const Duration(milliseconds: 400),
)
// Programmatic control
_controller.toMini(); // Collapse to icon-only
_controller.fromMini(); // Expand back
_controller.toggleMini();
You can also use NovaMiniDrawer directly for a fixed sidebar:
NovaMiniDrawer(
controller: _controller,
items: iconOnlyItems,
width: 64,
)
๐ Dynamic Data Loading
The drawer shows a shimmer skeleton automatically while loading:
// Required imports for the dynamic loading example:
// import 'dart:convert';
// import 'package:http/http.dart' as http;
// Load items from an API
await _controller.loadItems(() async {
final response = await http.get(Uri.parse('https://api.example.com/menu'));
final data = (jsonDecode(response.body) as List).cast<Map<String, dynamic>>();
return data
.map((e) => NovaDrawerItem(
id: e['id'] as String,
title: e['title'] as String,
icon: Icons.circle,
))
.toList();
});
// Load sections from an API
await _controller.loadSections(() async {
// ... fetch and return List<NovaDrawerSectionData>
});
// Error state is stored in controller.errorMessage
if (_controller.errorMessage != null) {
print('Failed: ${_controller.errorMessage}');
}
๐ RTL Support
RTL is automatically inferred from Directionality. To force RTL:
Directionality(
textDirection: TextDirection.rtl,
child: NovaDrawerScaffold(
controller: _controller,
drawer: NovaAppDrawer(
controller: _controller,
config: const NovaDrawerConfig(rtlSupport: true),
sections: _sections,
),
body: myBody,
),
)
โฟ Accessibility
NovaDrawer is built with accessibility first:
- Semantic labels for screen readers (TalkBack / VoiceOver)
- Focus traversal for keyboard and switch-access navigation
- Scalable text respects system font size settings
- Minimum touch targets (48 ร 48 logical pixels)
- Drawer open/close announcements for screen readers
NovaDrawerConfig(
accessibilityConfig: const NovaDrawerAccessibilityConfig(
enableSemantics: true,
enableFocusTraversal: true,
enableScalableText: true,
minimumTouchTarget: 48.0,
announceOnOpen: true,
announceOnClose: true,
drawerLabel: 'Main navigation drawer',
closeButtonLabel: 'Close navigation drawer',
),
)
Custom semantic labels per item:
NovaDrawerItem(
id: 'inbox',
title: 'Inbox',
icon: Icons.inbox,
badge: const NovaDrawerItemBadge(count: 12),
semanticLabel: 'Inbox, 12 unread messages',
)
๐ Package Structure
lib/
main.dart # Barrel export (library nova_drawer)
src/
models/
drawer_item.dart # NovaDrawerItem ยท NovaDrawerSectionData ยท NovaDrawerItemBadge
drawer_theme.dart # NovaDrawerTheme ยท NovaDrawerBadgeTheme
drawer_config.dart # NovaDrawerConfig ยท NovaDrawerAnimationType ยท NovaDrawerDisplayMode
header_config.dart # NovaHeaderConfig ยท NovaHeaderUserProfile ยท NovaHeaderAction
surface_config.dart # NovaDrawerSurfaceConfig ยท NovaDrawerSurface
content_config.dart # NovaDrawerStatItem ยท NovaDrawerShortcut ยท NovaDrawerRecentItem
# NovaDrawerFilterChip ยท NovaDrawerAppStatus ยท NovaDrawerWorkspace
controllers/
drawer_controller.dart # NovaDrawerController ยท NovaDrawerControllerProvider
headers/
nova_drawer_header.dart # NovaDrawerHeader (routes to variant widgets)
header_utils.dart # NovaHeaderWidgetUtils (shared helpers)
profile_header_*.dart # 10 individual header variant widgets
builders/
drawer_builders.dart # NovaDrawerBuilders (slot callbacks)
widgets/
advanced_app_drawer.dart # NovaAppDrawer (main widget)
drawer_header.dart # NovaDrawerHeaderWidget (legacy)
drawer_item_widget.dart # NovaDrawerItemWidget
drawer_section.dart # NovaDrawerSectionWidget
nested_menu_item.dart # NovaNestedMenuItem
mini_drawer.dart # NovaMiniDrawer
drawer_scaffold.dart # NovaDrawerScaffold
drawer_stats_card.dart # NovaDrawerStatsCard
drawer_shortcuts_grid.dart# NovaDrawerShortcutsGrid
drawer_recent_items.dart # NovaDrawerRecentItems
drawer_filter_chips.dart # NovaDrawerFilterChipsWidget
drawer_app_status.dart # NovaDrawerAppStatusWidget
drawer_workspace_switcher.dart # NovaDrawerWorkspaceSwitcher
animations/
animation_config.dart # NovaDrawerAnimationConfig
animation_wrapper.dart # NovaDrawerAnimationWrapper
*_animation.dart # 16 individual animation implementations
utils/
responsive_utils.dart # NovaResponsiveUtils ยท NovaDeviceType
accessibility_utils.dart # NovaAccessibilityUtils
backgrounds/
gradient_background.dart # NovaGradientBackground
particle_background.dart # NovaParticleBackground
deprecated_aliases.dart # @Deprecated typedefs for backward compatibility
๐ง API Reference
NovaDrawerController
| Method | Description |
|---|---|
open() |
Opens the drawer |
close() |
Closes the drawer (no-op when pinned) |
toggle() |
Toggles open/close |
pin() / unpin() / togglePin() |
Persistent pin control |
toMini() / fromMini() / toggleMini() |
Mini/icon-only mode |
selectItem(id) |
Select item by ID |
selectByRoute(path) |
Select item by route, auto-expands parents |
clearSelection() |
Clear active selection |
expandSection(id) / collapseSection(id) |
Section expand/collapse |
expandItem(id) / collapseItem(id) |
Nested item expand/collapse |
disableItem(id) / enableItem(id) |
Item enable state |
hideItem(id) / showItem(id) |
Item visibility |
setItems(items) |
Bulk-set items |
setSections(sections) |
Bulk-set sections |
loadItems(loader) |
Async dynamic item loading |
loadSections(loader) |
Async dynamic section loading |
| Property | Type | Description |
|---|---|---|
isOpen |
bool |
Whether drawer is open |
isPinned |
bool |
Whether drawer is pinned |
isMini |
bool |
Whether in mini mode |
isAnimating |
bool |
Animation in progress |
isLoading |
bool |
Data load in progress |
errorMessage |
String? |
Last load error |
selectedItemId |
String? |
Active item ID |
NovaAppDrawer
| Parameter | Type | Default | Description |
|---|---|---|---|
controller |
NovaDrawerController |
required | Drawer state manager |
sections |
List<NovaDrawerSectionData> |
[] |
Grouped menu items |
items |
List<NovaDrawerItem> |
[] |
Flat item list (when no sections) |
header |
Widget? |
null |
Header widget |
footer |
Widget? |
null |
Footer widget |
onItemTap |
Function(NovaDrawerItem)? |
null |
Item tap callback |
theme |
NovaDrawerTheme? |
null |
Visual theme |
config |
NovaDrawerConfig |
NovaDrawerConfig() |
Behavior configuration |
builders |
NovaDrawerBuilders? |
null |
Slot-based custom builders |
width |
double? |
auto | Override drawer width |
enableGradientBackground |
bool |
false |
Animated gradient backdrop |
gradientColors |
List<Color>? |
null |
Gradient color stops |
enableParticleBackground |
bool |
false |
Particle effect backdrop |
particleColor |
Color? |
null |
Particle color |
particleCount |
int |
20 |
Number of particles |
NovaHeaderConfig
| Property | Type | Default | Description |
|---|---|---|---|
variant |
NovaHeaderVariant |
classic |
Header style |
profile |
NovaHeaderUserProfile? |
null |
User data |
actions |
List<NovaHeaderAction> |
[] |
Action buttons |
showCloseButton |
bool |
true |
Show ร button |
showPinButton |
bool |
true |
Show pin button |
showEditProfileButton |
bool |
false |
Show edit shortcut |
showStatusIndicator |
bool |
true |
Show online status dot |
showNotificationBadge |
bool |
true |
Show notification count |
isLoading |
bool |
false |
Show skeleton shimmer |
isCollapsed |
bool |
false |
Collapsed state |
enableCollapseExpand |
bool |
false |
Allow toggling |
accounts |
List<NovaHeaderUserProfile> |
[] |
Extra accounts for stack |
gradientColors |
List<Color>? |
null |
For animatedGradient variant |
customHeaderBuilder |
Widget Function? |
null |
Fully custom header |
NovaDrawerItem
| Property | Type | Description |
|---|---|---|
id |
String |
Required unique identifier |
title |
String |
Required display text |
icon |
IconData? |
Default icon |
selectedIcon |
IconData? |
Icon when selected (falls back to icon) |
children |
List<NovaDrawerItem> |
Nested sub-items |
badge |
NovaDrawerItemBadge? |
Notification badge |
route |
String? |
Route path for selectByRoute() |
subtitle |
String? |
Secondary text |
tooltip |
String? |
Hover tooltip |
semanticLabel |
String? |
Screen reader label |
onTap |
VoidCallback? |
Tap callback |
isEnabled |
bool |
Interactive state |
isVisible |
bool |
Visibility |
initiallyExpanded |
bool |
Start expanded (nested) |
customWidget |
Widget? |
Replace entire item rendering |
leading |
Widget? |
Custom leading widget |
trailing |
Widget? |
Custom trailing widget |
metadata |
Map<String, dynamic>? |
Arbitrary extra data |
Enumerations
NovaDrawerAnimationType
slide ยท fade ยท scale ยท rotate ยท morph ยท elastic ยท spring ยท shimmer ยท blur ยท gradient ยท floating ยท floatingBounce ยท floatingReveal ยท wave ยท parallax ยท curtain
NovaDrawerDisplayMode
auto ยท overlay ยท push ยท side ยท mini
NovaHeaderVariant
classic ยท glassmorphism ยท compact ยท hero ยท expanded ยท animatedGradient ยท avatarStack ยท multiAction ยท statusAware ยท collapsible
NovaDrawerSurfaceStyle
plain ยท elevated ยท glassmorphism ยท blurred ยท gradient ยท premiumShadow ยท outlinedMinimal ยท neumorphic ยท imageBacked ยท animatedMeshGradient
NovaUserStatus
online ยท offline ยท busy ยท away ยท unknown
๐ Migration Guide
All public APIs were renamed from the old Drawer* / Advanced* prefix to the unified Nova* prefix. The old names remain available as deprecated typedefs in deprecated_aliases.dart and will be removed in v2.
Key renames
| Old Name | New Name |
|---|---|
AdvancedDrawerController |
NovaDrawerController |
AdvancedDrawerTheme |
NovaDrawerTheme |
AdvancedAppDrawer |
NovaAppDrawer |
DrawerScaffoldWidget |
NovaDrawerScaffold |
DrawerItem |
NovaDrawerItem |
DrawerItemBadge |
NovaDrawerItemBadge |
DrawerSectionData |
NovaDrawerSectionData |
DrawerConfig |
NovaDrawerConfig |
DrawerAnimationType |
NovaDrawerAnimationType |
DrawerAnimationConfig |
NovaDrawerAnimationConfig |
DrawerDisplayMode |
NovaDrawerDisplayMode |
DrawerBreakpoints |
NovaDrawerBreakpoints |
DrawerGestureConfig |
NovaDrawerGestureConfig |
DrawerAccessibilityConfig |
NovaDrawerAccessibilityConfig |
DrawerHeaderWidget |
NovaDrawerHeaderWidget |
DrawerStatsCard |
NovaDrawerStatsCard |
DrawerStatItem |
NovaDrawerStatItem |
DrawerShortcutsGrid |
NovaDrawerShortcutsGrid |
DrawerShortcut |
NovaDrawerShortcut |
DrawerRecentItems |
NovaDrawerRecentItems |
DrawerRecentItem |
NovaDrawerRecentItem |
DrawerFilterChips |
NovaDrawerFilterChipsWidget |
DrawerFilterChip |
NovaDrawerFilterChip |
DrawerAppStatusWidget |
NovaDrawerAppStatusWidget |
DrawerAppStatus |
NovaDrawerAppStatus |
DrawerWorkspaceSwitcher |
NovaDrawerWorkspaceSwitcher |
DrawerWorkspace |
NovaDrawerWorkspace |
DrawerSurface |
NovaDrawerSurface |
DrawerSurfaceConfig |
NovaDrawerSurfaceConfig |
DrawerSurfaceStyle |
NovaDrawerSurfaceStyle |
DrawerBuilders |
NovaDrawerBuilders |
MiniDrawerWidget |
NovaMiniDrawer |
NestedMenuItem |
NovaNestedMenuItem |
HeaderVariant |
NovaHeaderVariant |
HeaderAction |
NovaHeaderAction |
HeaderUserProfile |
NovaHeaderUserProfile |
UserStatus |
NovaUserStatus |
DrawerGradientBackground |
NovaGradientBackground |
DrawerParticleBackground |
NovaParticleBackground |
ResponsiveUtils |
NovaResponsiveUtils |
AccessibilityUtils |
NovaAccessibilityUtils |
DeviceType |
NovaDeviceType |
Old names still compile but produce deprecation warnings:
// โ ๏ธ Shows deprecation warning โ will be removed in v2
final c = AdvancedDrawerController();
// โ
Correct
final c = NovaDrawerController();
๐ License
MIT License. See LICENSE for details.
Libraries
- nova_drawer
- NovaDrawer โ A modern, fully dynamic, and highly responsive app drawer component for Flutter.