adaptive_dialog Dialogs & Action Sheets Guide
adaptive_dialog presents dialogs and action sheets adaptively matching the host platform (Cupertino style on iOS/macOS, Material Design 3 style on Android/Web/Desktop).
Guidelines
- Always Use Adaptive Helpers Over Raw Dialogs:
- Instead of handcrafting
showDialog(builder: (_) => AlertDialog(...))orshowCupertinoDialog, useshowOkAlertDialog,showOkCancelAlertDialog,showConfirmationDialog, orshowModalActionSheet.
- Instead of handcrafting
- Handling Results:
showOkCancelAlertDialog()returnsOkCancelResult.okorOkCancelResult.cancel. Always checkif (result == OkCancelResult.ok)rather than comparing against boolean or null.showModalActionSheet<T>()returns the generic keyT?associated with the chosenBottomSheetAction<T>. It returnsnullif dismissed.
- Destructive Actions:
- Set
isDestructiveAction: trueonBottomSheetActionorAlertDialogActionfor dangerous actions (e.g. Delete, Reset, Logout). This automatically applies platform-appropriate red text and emphasis.
- Set
- Text Input:
- Use
showTextInputDialog()to solicit one or more user inputs without manually wiringTextEditingControllerboilerplate and dialog state.
- Use
- Platform Overrides (Optional):
- If a uniform design across platforms is explicitly requested, pass
style: AdaptiveStyle.materialorstyle: AdaptiveStyle.cupertino.
- If a uniform design across platforms is explicitly requested, pass
Examples
1. Alert & Confirmations
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flutter/material.dart';
Future<void> confirmAccountDeletion(BuildContext context) async {
final result = await showOkCancelAlertDialog(
context: context,
title: 'Delete Account',
message: 'Are you sure you want to delete your account? This action cannot be undone.',
okLabel: 'Delete',
cancelLabel: 'Cancel',
isDestructiveAction: true,
);
if (result == OkCancelResult.ok) {
// Proceed with account deletion
}
}
2. Modal Action Sheet with Generic Keys
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flutter/material.dart';
enum PostAction { edit, share, delete }
Future<void> showPostMenu(BuildContext context) async {
final action = await showModalActionSheet<PostAction>(
context: context,
title: 'Post Options',
actions: const [
BottomSheetAction(title: 'Edit Post', key: PostAction.edit, icon: Icons.edit),
BottomSheetAction(title: 'Share', key: PostAction.share, icon: Icons.share),
BottomSheetAction(
title: 'Delete Post',
key: PostAction.delete,
icon: Icons.delete,
isDestructiveAction: true,
),
],
);
switch (action) {
case PostAction.edit:
// Handle edit
break;
case PostAction.share:
// Handle share
break;
case PostAction.delete:
// Handle delete
break;
case null:
// User tapped outside or dismissed
break;
}
}
3. Text Input Dialog
import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:flutter/material.dart';
Future<void> renameItem(BuildContext context, String currentName) async {
final inputs = await showTextInputDialog(
context: context,
title: 'Rename Item',
textFields: [
DialogTextField(
initialText: currentName,
hintText: 'Enter new name',
validator: (value) =>
(value == null || value.trim().isEmpty) ? 'Name cannot be empty' : null,
),
],
);
if (inputs != null && inputs.isNotEmpty) {
final newName = inputs.first;
print('Renamed to: $newName');
}
}
Common Pitfalls & Anti-Patterns
- ❌ Anti-pattern: Writing
Platform.isIOS ? CupertinoAlertDialog(...) : AlertDialog(...)manually, which is fragile, misses macOS/Web adaptations, and creates repetitive boilerplate.- ✔️ Correct: Use
showOkAlertDialogorshowOkCancelAlertDialog.
- ✔️ Correct: Use
- ❌ Anti-pattern: Forgetting to check for
nullwhenshowModalActionSheetis dismissed without selection.- ✔️ Correct: Always handle the
nullcase gracefully.
- ✔️ Correct: Always handle the