Showing AlertDialog Without Context in Flutter
FlutterPulseThis article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!π

Issue: Showing an AlertDialog Without Context
Issue: Showing an AlertDialog Without Context
In Flutter, the showDialog function requires a BuildContext parameter. However, if we want to show an AlertDialog from an async function (like an HTTP request failure inside getNews()), we may not always have direct access to context.
Common Mistake: Trying to Show a Dialog Without Context
A common mistake beginners make is attempting to show a dialog directly inside an async function without passing a valid context. For example:
void getNews() async {
try {
throw Exception("Failed to load news");
} catch (e) {
print("Error: \$e");
showDialog(
context: context, // β Error: context is not available here
builder: (context) => AlertDialog(
title: Text("Error"),
content: Text("Something went wrong!"),
),
);
}
}This code will not work because context is not available in an independent function.
Solution: Using GlobalKey<NavigatorState>
To solve this, we can use a global navigatorKey. This allows us to access the BuildContext globally and show a dialog from anywhere in the app, even inside an async function.
Step-by-Step Guide
Step 1: Define a Global Navigator Key
A global navigator key allows us to manage navigation without requiring context. Declare it at the very top of your main.dart file, outside any classes:
import 'package:flutter/material.dart';
// β Correct: Declare the global navigator key at the top
final navigatorKey = GlobalKey<NavigatorState>();
Step 2: Assign It to MaterialApp
When initializing the MaterialApp, assign the navigatorKey to it:
void main() => runApp(
MaterialApp(
home: HomePage(),
navigatorKey: navigatorKey, // β Assign the global navigator key
),
);
Step 3: Create a Function to Show the AlertDialog
Now, create a function that can be called from anywhere in the app to display an AlertDialog:
void showMyDialog() {
showDialog(
context: navigatorKey.currentContext!, // β
Using the global context
builder: (context) => AlertDialog(
title: Text("Error"),
content: Text("Something went wrong!"),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text("OK"),
),
],
),
);
}Step 4: Trigger the Dialog on HTTP Failure
In your async function, call showMyDialog() when an error occurs:
Future<void> getNews() async {
try {
// Simulating an HTTP request
throw Exception("Failed to load news");
} catch (e) {
print("Error: \$e"); // β
Log the error
showMyDialog(); // β
Show AlertDialog
}
}Step 5: Full Working Code Example
Here is a complete example so beginners can see how everything fits together:
import 'package:flutter/material.dart';
final navigatorKey = GlobalKey<NavigatorState>();
void main() {
runApp(MaterialApp(
home: HomePage(),
navigatorKey: navigatorKey,
));
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Home")),
body: Center(
child: ElevatedButton(
onPressed: getNews,
child: Text("Fetch News"),
),
),
);
}
}
void showMyDialog() {
showDialog(
context: navigatorKey.currentContext!,
builder: (context) => AlertDialog(
title: Text("Error"),
content: Text("Something went wrong!"),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text("OK"),
),
],
),
);
}
Future<void> getNews() async {
try {
throw Exception("Failed to load news");
} catch (e) {
print("Error: \$e");
showMyDialog();
}
}
Why This Works
- β Wrong Approach: Using
contextinside an async function. - β
Correct Approach: Using
navigatorKeyto get the globalcontext. - The
showMyDialog()function can be called from anywhere, including async functions. - This approach helps avoid the need to pass
contextexplicitly, making the code cleaner.