Loader System
GoRouter Modular shows a loading indicator automatically while module binds are being resolved. This is especially useful for modules with async dependencies.
Automatic Loading
The loader appears automatically during:
- Module bind registration (including async binds)
- Route transitions that depend on
goAsync/pushAsync
No setup is required for the default behavior.
Manual Control
You can show or hide the loader programmatically:
ModularLoader.show();
// Perform async work...
ModularLoader.hide();Custom Loader Widget
Replace the default loader with your own widget using ModularApp.router:
class AppWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ModularApp.router(
title: 'My App',
builder: (context, child) => Stack(
children: [
child!,
ModularLoader.builder(context, child),
],
),
);
}
}You can also provide a fully custom overlay:
ModularApp.router(
title: 'My App',
builder: (context, child) => Stack(
children: [
child!,
ValueListenableBuilder<bool>(
valueListenable: ModularLoader.isLoading,
builder: (context, loading, _) {
if (!loading) return const SizedBox.shrink();
return Container(
color: Colors.black54,
child: const Center(
child: CircularProgressIndicator(color: Colors.white),
),
);
},
),
],
),
);When the Loader Appears
| Scenario | Loader shown? |
|---|---|
| Navigating to a module with sync binds | Briefly (usually imperceptible) |
| Navigating to a module with async binds | Yes, until all binds resolve |
Using goAsync() / pushAsync() | Yes, until onComplete fires |
Calling ModularLoader.show() manually | Yes, until ModularLoader.hide() |
Best Practices
- Let it work automatically — The default behavior covers most cases.
- Use async binds for heavy initialization — Database connections, API token refresh, etc.
- Keep initialization fast — Users should not wait more than a second or two.
- Test on slow connections — Simulate latency to verify the loader appears correctly.