context_show 0.3.3
context_show: ^0.3.3 copied to clipboard
A lightweight and flexible Flutter package for showing custom overlays, banners, toasts and dialogs with simple, context-based extension. Highly customizable and easy to use.
A Flutter package that provides a simple and powerful way to show custom overlays, toasts, banners, snackbars, dialogs etc. using the BuildContext.
Introduction #
context_show simplifies the process of displaying temporary widgets on the screen. It extends BuildContext with a show() method that allows you to render any widget as an overlay, with full control over alignment, duration, and animations.
Say goodbye to boilerplate code for managing OverlayEntry and AnimationController.
Features #
- 🪄 Simple API: Show your widget with a single line of code:
context.show(...). - 🎯 Flexible alignment – display widgets at any screen position (
top,bottom,center, etc.). - 🎨 Customizable transitions –
fade,scale,slide,rotate, or compose your own. - 🧩 Composable animations – chain multiple transitions fluently
.fade().scale().rotation(). - 🎛️ Programmatic control – close overlays from anywhere using
context.close()with flexible selectors. - 🖼️ Custom Background: add custom backgrounds or animated backdrops.
- 📐 Safe area, your way – inset below the app bar by default, or draw edge to edge over it with
safeArea: false. - 👆 Dismissible overlays – tap outside to close with ease.
- ⏱️ Auto-dismiss – control duration or disable with
Duration.zero. - ✅ Type-safe results – returns a
Future<T?>that resolves when the overlay closes. - ⚡ Lightweight – zero dependencies, built on pure
Flutter.
Usage Examples #
| Simple blue toast that slides up from the bottom and auto-dismisses after 4 seconds. | |
|---|---|
|
|
| Green banner that slides down from the top and can be only closed by clicking on the close icon button. | |
|
|
| Showing multiple banners with random color and random alignment and closing them with context.close() | |
|
|
| Showing Flutter logo in the center with a rotation animation, on a dimmed, dismissible background | |
|
|
| Displays a small red banner at the top center, aligned with the app bar and safe area insets. It slides in from below with a rotation effect, over a reddish, dismissible background | |
|
|
Positioning: Safe Area vs. Full Screen #
The overlay always spans the entire screen, app bar and status bar included. Nothing is clipped — safeArea, margin and backgroundMargin only decide where your widget sits inside it. So drawing over the chrome is fully supported, not a workaround.
Below the chrome (default) #
Content is inset so it clears the status bar, app bar and bottom bar:
context.show((_) => Text('Banner'), alignment: Alignment.topCenter);
Over the app bar and status bar #
Opt out of the automatic inset to go edge to edge — useful for full-screen dialogs, dimmed backdrops, or a banner that deliberately covers the app bar:
context.show(
(_) => Text('Covers everything'),
safeArea: false,
alignment: Alignment.topCenter,
);
Anywhere in between #
Pass an explicit margin to clear only what you want:
context.show(
(_) => Text('Custom inset'),
margin: const EdgeInsets.only(top: 40),
alignment: Alignment.topCenter,
);
margin always wins over safeArea.
Note: don't reach for
MediaQuery.paddingOf(context).topto get the status bar height here — inside aScaffoldbody theScaffoldhas already consumed it, so bothpaddingOfandviewPaddingOfreturn zero and your overlay lands at the very top. Useoverlay.safeAreainstead, which is measured against the chrome the overlay actually appears over.
Per-edge control #
overlay.safeArea is handed to the builder and stays available even with safeArea: false, so you can apply the insets selectively:
context.show(
(overlay) => Padding(
// Clear the bottom bar, but let the content run under the app bar.
padding: EdgeInsets.only(bottom: overlay.safeArea.bottom),
child: Text('Banner'),
),
safeArea: false,
);
Full-bleed background, inset content #
backgroundMargin is independent of margin, so a backdrop can cover the whole screen while the content stays clear of the chrome:
context.show(
(_) => Card(child: Text('Inset content')),
background: (_) => Container(color: Colors.black54),
backgroundMargin: EdgeInsets.zero, // dim the app bar too
dismissible: true,
);
Note: a
Containerwith only a color expands to fill the space, which is what you usually want here. A widget that sizes itself to its child —ColoredBox, for instance — collapses instead, since the background is positioned by anAlign. Wrap it in aSizedBox.expandif you hit that.
The insets are resolved from the Scaffold your overlay appears over, whether you call show from inside the body or from the page's own build context.
They are also measured against the Overlay the entry actually lands in. If you use a nested Navigator — a per-tab navigator inside a shell, say — its overlay already starts below the app bar, and the insets account for that instead of clearing the same app bar twice.
Closing Overlays Programmatically #
The context.close() method allows you to close overlays from anywhere in your code. You can close individual overlays, multiple overlays, or all overlays at once using flexible selectors.
Basic Usage #
// Close the last shown overlay (default behavior)
context.close();
Closing Specific Overlays #
Use the Overlays class to target specific overlays:
// Close the first overlay
context.close(Overlays.first());
// or
context.close((overlays) => overlays.first);
// Close the last overlay
context.close();
// or
context.close(Overlays.last());
// or
context.close((overlays) => overlays.last);
// Close all overlays
context.close(Overlays.all());
// or
context.close((overlays) => overlays);
Closing Overlays by ID #
Assign an id when showing an overlay, then close it by that ID:
// Show overlay with an ID
context.show(
(_) => MyWidget(),
id: 'my-banner',
);
// Close specific overlay by ID
context.close(Overlays.first(id: 'my-banner'));
//or
context.close((overlays) => overlays.byId('my-banner').first);
// Close all overlays with the same ID
context.close(Overlays.all(id: 'notification'));
//or
context.close((overlays) => overlays.byId('notification'));
Custom Selectors #
Use a custom function to select which overlays to close:
// Close all overlays by ID using a custom selector
context.close((overlays) => overlays.byId('banner-1'));
// Close the first overlay matching a condition
context.close((overlays) => overlays.first);
// Close multiple overlays with custom logic
context.close((overlays) => overlays.where((o) => o.id?.startsWith('temp-') ?? false));
Returning Results from Overlays #
You can return values when closing overlays from anywhere in your code:
class Page extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
ElevatedButton(
child: Text('Show'),
onPressed: () async {
// Show overlay and await the result
final result = await context.show<String>((_) => Text('Banner'));
print('$result'); // SOME RESULT
},
),
ElevatedButton(
child: Text('Close with Result'),
onPressed: () {
// Close overlay from a different callback and return some value:
context.close('SOME RESULT');
},
),
],
),
);
}
}
Real-World Example: No Internet Banner #
// Show a "no internet" banner
void showNoInternetBanner(BuildContext context) {
context.show(
(_) => Container(
color: Colors.orange,
padding: EdgeInsets.all(20),
child: Text('No Internet Connection'),
),
id: 'no-internet',
duration: Duration.zero, // Won't close automatically
);
}
// Close it when connection is restored from anywhere in the app
// BuildContext can be completely different - any context works
void onConnectionRestored(BuildContext context) {
context.close((overlays) => overlays.byId('no-internet'));
// or use this syntax:
context.close(Overlays.all(id: 'no-internet'));
}

