Dialogs
CDX dialogs are composed from five primitives: DialogShell glues them together, and ConfirmationDialog provides the four canonical flavors. Custom dialogs use the primitives directly.
ConfirmationDialog
Four named factories cover the standard cases. Always invoked through Flutter's showDialog.
| Factory | Variant | Buttons |
|---|---|---|
.info | standard | OK |
.error | error | OK |
.confirm | primary | Cancel + Confirm |
.destructive | destructive | Cancel + Confirm (error palette) |
final result = await showDialog<bool>(
context: context,
builder: (_) => ConfirmationDialog.destructive(
title: 'Delete area?',
description: 'This action cannot be undone.',
confirmLabel: 'Delete',
onCancel: () => Navigator.of(context).pop(false),
onConfirm: () => Navigator.of(context).pop(true),
),
);
// Info — single OK button
await showDialog<void>(
context: context,
builder: (_) => ConfirmationDialog.info(
title: 'Submitted',
description: 'Your request has been submitted for approval.',
onDismiss: () => Navigator.of(context).pop(),
),
);Optional body
Both .confirm and .destructive accept a body widget rendered below the description — use it for inline forms, e-signature inputs, or additional context.
ConfirmationDialog.confirm(
title: 'Approve change',
description: 'Sign with your initials to approve.',
confirmLabel: 'Approve',
isDisabled: initials.value.isEmpty,
isLoading: store.isSubmitting,
onCancel: () => Navigator.of(context).pop(),
onConfirm: () async => await store.approve(initials.value),
body: TextField(
decoration: const InputDecoration(labelText: 'Initials'),
controller: initials,
),
)DialogShell
The base container — modal barrier, sizing, header divider, and footer auto-wiring. Use it directly when you need a custom body or footer layout.
showDialog<void>(
context: context,
builder: (_) => DialogShell(
title: 'Edit profile',
icon: FluentIcons.person_edit_24_regular,
width: 720,
maxHeight: 600,
headerActions: [Button.icon(icon: FluentIcons.history_24_regular, ...)],
footerMessage: const DialogMessage(
text: 'Changes apply immediately.',
severity: MessageSeverity.info,
),
actions: [
DialogAction.cancel(onPressed: () => Navigator.pop(context)),
DialogAction.primary(label: 'Save', onPressed: _save),
],
content: const ProfileForm(),
),
);Parameters
| Param | Type | Default |
|---|---|---|
title / titleWidget | String? / Widget? | One required |
icon / iconColor | IconData? / Color? | null |
variant | DialogVariant | standard |
content | Widget | required |
actions | List<DialogAction>? | null (no footer) |
headerActions | List<Widget>? | null |
footerMessage | DialogMessage? | null |
width | double? | 600 |
maxHeight | double? | 500 |
showCloseButton | bool? | variant default |
onClose | VoidCallback? | Navigator.pop |
Primitives
DialogVariant
enum DialogVariant { standard, primary, destructive, error }Drives header background and close-button visibility:
| Variant | Header bg | Default close button |
|---|---|---|
standard | surfaceContainerHighest + tinted icon circle | shown |
primary | primaryContainer + onPrimaryContainer foreground | hidden |
destructive | errorContainer + onErrorContainer | hidden |
error | errorContainer + onErrorContainer | shown |
DialogHeader
DialogHeader(
title: 'Edit area',
icon: FluentIcons.edit_24_regular,
variant: DialogVariant.primary,
onClose: () => Navigator.pop(context),
actions: [const _HistoryButton()],
leading: IconButton(icon: const Icon(FluentIcons.arrow_left_24_regular), onPressed: ...),
)leading is reserved for back-arrow affordances (used by CdxPanelPage). actions render before the close button.
DialogFooter / DialogAction
DialogFooter(
message: const DialogMessage(text: 'All fields required.', severity: MessageSeverity.warning),
actions: [
DialogAction.cancel(onPressed: () => Navigator.pop(context)),
DialogAction.primary(label: 'Save', icon: FluentIcons.save_24_regular, onPressed: _save),
],
)DialogAction factories — .cancel, .ok, .primary, .destructive. Each carries isLoading / isDisabled for primary/destructive variants.
DialogMessage / MessageSeverity
Inline message banner inside the footer. MessageSeverity.error / warning / success / info maps to the matching Container palette (errorContainer, tertiaryContainer, etc.).