s_modal 1.0.2
s_modal: ^1.0.2 copied to clipboard
A package for displaying highly customizable modal overlays including sheets, dialogs, and snackbars... with independent lifecycle management.
s_modal #
A comprehensive, production-ready Flutter package for displaying beautiful and highly customizable modal overlays including sheets, dialogs, and snackbars with independent lifecycle management.

β¨ Features #
π― Three Core Modal Types #
Sheets (Bottom, Top, Left, Right)
- π Slide in from any edge (bottom, top, left, right)
- π Expandable with drag-to-expand functionality
- π¨ Customizable size, colors, and borders
- π Interactive drag handle
- π± Auto-sizing based on content
Dialogs
- π― Centered positioning with optional offset
- π±οΈ Optional draggable functionality
- π Smooth fade and scale animations
- π¨ Fully customizable styling
Snackbars
- π Position anywhere on screen (9 alignment options + custom offset)
- π Multiple display modes: staggered, notification bubble, queued, replace
- β±οΈ Auto-dismiss with visual duration indicator
- π Swipe-to-dismiss (horizontal and vertical)
- π¨ Rich customization with icons, colors, and actions
π Advanced Features #
- Independent Lifecycles: Each modal type has its own controller - snackbars don't interfere with dialogs!
- Live Updates: Modify modal properties in real-time with
updateParams() - ID-Based Management: Dismiss specific modals by ID, check which are active
- Hot Reload Support:
ModalBuilderwidget for seamless development - Background Effects: Blur and dim background with customizable intensity
- Smart Dismissal: Tap outside, swipe, or programmatic control
- Callbacks:
onDismissed,onExpanded, andonTaphooks - Type-Safe API: Enums for positions, animations, and display modes
- Zero Dependencies Conflicts: Carefully selected dependencies for maximum compatibility
π¦ Installation #
Add this to your package's pubspec.yaml file:
dependencies:
s_modal: ^1.0.2
Then run:
flutter pub get
π Quick Start #
1. Wrap your app with Modal.activator #
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Modal.activator(
child: MaterialApp(
home: MyHomePage(),
),
);
}
}
2. Show your first modal #
// Simple bottom sheet
Modal.show(
builder: () => Container(
padding: EdgeInsets.all(20),
child: Text('Hello, Modal!'),
),
);
// Simple snackbar
Modal.showSnackbar(
text: 'Operation successful!',
prefixIcon: Icons.check_circle,
backgroundColor: Colors.green,
);
π Usage Examples #
Bottom Sheet #
Modal.show(
builder: () => YourContentWidget(),
modalType: ModalType.sheet,
size: 300, // Height in pixels
isExpandable: true,
expandedPercentageSize: 85, // Max 85% of screen height
shouldBlurBackground: true,
backgroundColor: Colors.white,
onDismissed: () => print('Sheet dismissed'),
);
Side Sheet (Left or Right) #
Modal.show(
builder: () => MenuWidget(),
modalType: ModalType.sheet,
sheetPosition: SheetPosition.left, // or .right
size: 280, // Width in pixels
shouldBlurBackground: true,
);
Dialog #
Modal.show(
builder: () => AlertDialogContent(),
modalType: ModalType.dialog,
modalPosition: Alignment.center,
isDraggable: true,
shouldBlurBackground: true,
blurAmount: 5.0,
);
Snackbar with Duration Indicator #
Modal.showSnackbar(
text: 'File downloaded successfully',
prefixIcon: Icons.download_done,
backgroundColor: Colors.blue.shade800,
duration: Duration(seconds: 3),
position: Alignment.topCenter,
showDurationTimer: true,
durationTimerDirection: DurationIndicatorDirection.leftToRight,
durationTimerColor: Colors.cyan,
);
Staggered Snackbars #
// Show multiple snackbars that stack
Modal.showSnackbar(
text: 'First notification',
displayMode: SnackbarDisplayMode.staggered,
maxStackedSnackbars: 5,
);
Modal.showSnackbar(
text: 'Second notification',
displayMode: SnackbarDisplayMode.staggered,
);
Using ModalBuilder (Recommended for Development) #
// With hot reload support!
ModalBuilder(
builder: () => MyBottomSheetContent(),
size: 350,
shouldBlurBackground: true,
onDismissed: () => print('Dismissed'),
child: ElevatedButton(
child: Text('Show Sheet'),
),
)
// Dialog variant
ModalBuilder.dialog(
builder: () => MyDialogContent(),
shouldBlurBackground: true,
child: ElevatedButton(
child: Text('Show Dialog'),
),
)
Live Updates with updateParams() #
// Show a dialog
Modal.show(
id: 'my_dialog',
builder: () => DialogContent(),
modalType: ModalType.dialog,
blurAmount: 3.0,
);
// Later, update it without recreation
Modal.updateParams(
id: 'my_dialog',
blurAmount: 8.0,
isDraggable: true,
);
ID-Based Dismissal #
// Show modals with IDs
Modal.show(
id: 'settings_sheet',
builder: () => SettingsWidget(),
);
Modal.showSnackbar(
id: 'notification_1',
text: 'New message',
);
// Dismiss specific modal
await Modal.dismissById('settings_sheet');
// Check if active
if (Modal.isModalActiveById('notification_1')) {
// Modal is showing
}
Mixed Modal Interactions #
// Show a sheet, then a snackbar
Modal.show(
builder: () => BottomSheetContent(),
modalType: ModalType.sheet,
);
// Snackbar appears above the sheet!
Modal.showSnackbar(
text: 'Changes saved',
position: Alignment.topCenter,
);
π¨ Customization #
Sheet Positions #
// Available positions
SheetPosition.bottom // Slides from bottom
SheetPosition.top // Slides from top
SheetPosition.left // Slides from left
SheetPosition.right // Slides from right
Snackbar Positions #
// 9 Standard alignments
Alignment.topLeft
Alignment.topCenter
Alignment.topRight
Alignment.centerLeft
Alignment.center
Alignment.centerRight
Alignment.bottomLeft
Alignment.bottomCenter
Alignment.bottomRight
// Custom offset positioning
Modal.showSnackbar(
text: 'Custom position',
offset: Offset(100, 200), // x, y from top-left
);
Snackbar Display Modes #
SnackbarDisplayMode.staggered // Stack visually with offset
SnackbarDisplayMode.notificationBubble // Collapsible bubble with counter
SnackbarDisplayMode.queued // Show one at a time, queue others
SnackbarDisplayMode.replace // New snackbar replaces current
Background Effects #
Modal.show(
builder: () => MyWidget(),
shouldBlurBackground: true,
blurAmount: 5.0, // 0-20, higher = more blur
barrierColor: Colors.black.withOpacity(0.5),
blockBackgroundInteraction: true, // Block taps on background
);
π― Advanced Features #
Type-Specific Controllers #
// Check specific modal types
if (Modal.isDialogActive) { /* ... */ }
if (Modal.isSheetActive) { /* ... */ }
if (Modal.isSnackbarActive) { /* ... */ }
// Get active IDs by type
List<String> snackbarIds = Modal.getActiveIdsByType(ModalType.snackbar);
// Dismiss by type
await Modal.dismissByType(ModalType.dialog);
Callbacks #
Modal.show(
builder: () => MyWidget(),
onDismissed: () {
print('Modal closed');
// Cleanup or show next modal
},
onExpanded: () {
print('Sheet expanded');
// Load more content
},
);
Modal.showSnackbar(
text: 'Notification',
onTap: () {
print('Snackbar tapped');
// Handle tap
},
onDismissed: () {
print('Snackbar dismissed');
},
);
Reactive Content #
// Using states_rebuilder for reactive content
final counter = RM.inject(() => 0);
Modal.show(
builder: () => OnReactive(
() => Text('Count: ${counter.state}'),
),
);
// Update triggers rebuild
counter.state++;
π API Reference #
Core Methods #
| Method | Description |
|---|---|
Modal.show() |
Display any modal type with full customization |
Modal.showSnackbar() |
Convenient snackbar with pre-styled options |
Modal.dismiss() |
Dismiss the active modal |
Modal.dismissById() |
Dismiss a specific modal by ID |
Modal.dismissAll() |
Dismiss all modals |
Modal.dismissByType() |
Dismiss all modals of a specific type |
Modal.updateParams() |
Update modal properties in real-time |
State Checks #
| Property | Description |
|---|---|
Modal.isActive |
Any modal is currently showing |
Modal.isDialogActive |
A dialog is showing |
Modal.isSheetActive |
A sheet is showing |
Modal.isSnackbarActive |
A snackbar is showing |
Modal.activeModalId |
ID of the current modal |
Modal.allActiveModalIds |
List of all active modal IDs |
Enums #
// Modal types
ModalType.sheet
ModalType.dialog
ModalType.snackbar
ModalType.custom
// Sheet positions
SheetPosition.bottom
SheetPosition.top
SheetPosition.left
SheetPosition.right
// Snackbar display modes
SnackbarDisplayMode.staggered
SnackbarDisplayMode.notificationBubble
SnackbarDisplayMode.queued
SnackbarDisplayMode.replace
// Duration indicator direction
DurationIndicatorDirection.leftToRight
DurationIndicatorDirection.rightToLeft
π Examples #
Check out the example folder for comprehensive demos including:
- Sheet Configurator: Interactive playground for all sheet types and options
- Dialog Configurator: Test all dialog features and configurations
- Snackbar Configurator: Explore all snackbar display modes and styles
- Modal Mixing: Examples of combining different modal types
- Reactive State: Using reactive state management with modals
- Live Updates: Dynamic parameter updates demo
Run the example app:
cd example
flutter run
π€ Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
π License #
This project is licensed under the MIT License - see the LICENSE file for details.
π Acknowledgments #
Built with:
- states_rebuilder_extended - State management
- flutter_animate - Smooth animations
- sizer - Responsive sizing
π Support #
- π Report bugs
- π‘ Request features
- π Documentation
Made with β€οΈ by SoundSliced ltd