Flutter: SnackBar and SnackBarAction Usage
Last updated:
6 min read

A SnackBar is the short message that reports the result of an action without interrupting the flow: it slides in at the bottom of the screen, stays for a few seconds and disappears on its own. We use it for things like "Saved", "Connection lost" or "Item deleted". With SnackBarAction you can add a single button to it, and the classic example is "Undo".
Live Demo
You can try this widget in the interactive example below:
💡 If the example above doesn't load, click DartPad to run it in a new tab.
Basic Usage
A SnackBar is shown through ScaffoldMessenger:
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Profile updated'),
),
);Older tutorials still show Scaffold.of(context).showSnackBar(...). That method was removed from Flutter; try it today and you get the compile error "The method 'showSnackBar' isn't defined for the type 'ScaffoldState'". Because ScaffoldMessenger belongs to the app rather than to a single Scaffold, the SnackBar stays visible even if the page changes while it is showing. That is exactly what we need in flows where the user taps "Save" and lands back on the previous page.
SnackBarAction Usage
It adds one button the user can press next to the message:
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Item deleted'),
action: SnackBarAction(
label: 'UNDO',
onPressed: () {
// Undo operation
},
),
),
);Pressing the button closes the SnackBar automatically. There is only one action and it should be short. If you need to offer two choices, the component you are looking for is a dialog, not a SnackBar.
Important Properties
| Property | Description |
|---|---|
content |
SnackBar content (usually Text) |
action |
Clickable button (SnackBarAction) |
duration |
Display duration (4 seconds by default) |
backgroundColor |
Background color |
behavior |
fixed or floating |
shape |
Shape (corner radius, etc.) |
margin |
Margins in floating mode |
showCloseIcon |
Adds a close icon on the right |
Floating SnackBar
Instead of sticking to the bottom edge, the SnackBar floats with space around it:
SnackBar(
content: const Text('Floating SnackBar'),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
margin: const EdgeInsets.all(16),
)If the whole app should look like this, move it into the theme instead of repeating it on every call: ThemeData(snackBarTheme: const SnackBarThemeData(behavior: SnackBarBehavior.floating)).
SnackBar with Icon
SnackBar(
content: Row(
children: const [
Icon(Icons.info, color: Colors.white),
SizedBox(width: 10),
Expanded(child: Text('Information message')),
],
),
backgroundColor: Colors.blue,
)Wrapping the text in Expanded matters. Without it, a long message makes the Row overflow to the right; the Expanded post explains why.
Programmatically Closing SnackBar
showSnackBar returns a controller. When we want to close the message ourselves after a long operation, we set a long duration and call close() once the work is done:
final snackBar = ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Loading...'),
duration: Duration(minutes: 1),
),
);
// Close when operation completes
await someAsyncOperation();
snackBar.close();When to Use It and When Not To
A SnackBar is for information the user can afford to miss. This is the distinction I use:
- Use it to confirm a finished action, for operations that can be undone, and for temporary network errors.
- Don't use it when the user has to decide something. The message is gone after four seconds; a question like a delete confirmation needs an AlertDialog.
- Don't use it for persistent states. Information such as "You are offline", which must stay until the problem is solved, fits a
MaterialBannershown withScaffoldMessenger.of(context).showMaterialBanner(...). - Don't use it for form validation errors. "Invalid email" belongs right under the field via
validator, so the user never has to hunt for the field that is wrong.
Common Mistakes
1. Messages piling up in a queue
Symptom: the user taps a button five times quickly, the SnackBars are shown one after another, and the last one is still on screen twenty seconds later.
Cause: ScaffoldMessenger queues messages; a new one waits for the previous one to finish.
Fix: hide the current one before showing the next. Dart's cascade (..) syntax is handy here:
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(const SnackBar(content: Text('Added to cart')));clearSnackBars() removes everything that is waiting.
2. Setting margin with fixed behavior
Symptom: the app stops with the assertion "Margin can only be used with floating behavior".
Fix: margin and width only work together with behavior: SnackBarBehavior.floating. Either switch the behavior to floating or drop those parameters. Passing both of them at once is an error too; pick one.
3. Using context after an await
Symptom: the analyzer reports use_build_context_synchronously, and if the user left the page while the request was running you get a runtime error.
Fix: there are two options. Check context.mounted after the await, or grab the messenger before the await:
Future<void> _save() async {
final messenger = ScaffoldMessenger.of(context);
await repository.save(profile);
messenger.showSnackBar(const SnackBar(content: Text('Saved')));
}The nice thing about the second option is that the message can still be shown even if the page has been closed.
4. Showing a SnackBar in initState
Symptom: the error "dependOnInheritedWidgetOfExactType … was called before initState() completed".
Cause: while initState runs, the widget is not fully attached to the tree yet, so the ScaffoldMessenger.of(context) lookup is not allowed. The order of these phases is covered in the lifecycle post.
Fix: postpone it until after the first frame:
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Welcome back')),
);
});
}Mini Scenario: Delete with Undo
Picture a task list. When the user deletes a task we do not ask for confirmation; we remove it from the list right away and offer "Undo". The real deletion on the server only happens after the SnackBar is gone. The controller returned by showSnackBar has a closed field, a Future that tells us why the SnackBar closed:
Future<void> _removeTask(int index) async {
final task = _tasks[index];
final messenger = ScaffoldMessenger.of(context);
setState(() => _tasks.removeAt(index));
messenger.hideCurrentSnackBar();
final controller = messenger.showSnackBar(
SnackBar(
content: Text('"${task.title}" deleted'),
action: SnackBarAction(label: 'UNDO', onPressed: () {}),
),
);
final reason = await controller.closed;
if (reason == SnackBarClosedReason.action) {
if (!mounted) return;
setState(() => _tasks.insert(index, task)); // Put it back where it was
} else {
await widget.repository.delete(task.id); // Timed out, swiped away, etc.
}
}onPressed is empty because SnackBarClosedReason.action already tells us the button was pressed. When another delete comes in, hideCurrentSnackBar() closes the previous SnackBar and that task is deleted for good, so only the most recent delete can be undone and index always stays valid. One caveat: if the app is killed during those few seconds, the delete request never reaches the server. Where the data is critical, it is safer to delete for real first and recreate the record on "Undo".
The pattern also works fine when the list has a FloatingActionButton; the Scaffold makes sure the two do not overlap.
Frequently Asked Questions
How long does a SnackBar stay on screen?
The default is 4 seconds. You can change it with the duration parameter, and it is worth extending a little for messages that take time to read or contain an action.
Can I show a SnackBar without a context?
Yes. Create a GlobalKey<ScaffoldMessengerState> and pass it to the scaffoldMessengerKey parameter of MaterialApp. After that you can call key.currentState?.showSnackBar(...) from anywhere.
What is the difference between a SnackBar and a Toast?
Flutter has no built-in Toast widget; the Material equivalent is the SnackBar. A SnackBar is drawn inside your app's own widget tree, can carry an action button and follows your theme. An Android-style toast requires an extra package.
Can several SnackBars be visible at the same time?
No, only one is visible at a time and the others wait in a queue. Call hideCurrentSnackBar() first if the new message should appear immediately.
Related Posts
Flutter: BottomSheet and showModalBottomSheet
Flutter's showModalBottomSheet: returning values, isScrollControlled, useSafeArea, showDragHandle, keyboard insets, DraggableScrollableSheet, persistent sheets.
Flutter: PopupMenuButton Usage and Menu Structures
Flutter PopupMenuButton for overflow menus: type-safe enums, onSelected vs onTap, a list row scenario and the mistakes to avoid.
Flutter: Card Widget and Design Usage
Flutter Card guide: Material 3 Card.filled and Card.outlined, clipBehavior with images, tappable cards with InkWell, common mistakes and a product card.