RemixRemix
Overlays

Dialog

A modal dialog component for focused decisions, confirmations, and custom content

Open catalog
Starting Flutter example…
Live Flutter from this checkout’s component catalog. Examples include Fortal styling; the source tab shows the catalog code, not a standalone application.

A modal dialog component for focused content and actions.

When to use this

  • Confirmations: Ask users to confirm destructive or important actions
  • Focused forms: Collect a small amount of information without leaving the current screen
  • Alerts: Present information that needs immediate attention
  • Custom modal content: Render a fully custom body inside Remix dialog chrome

Basic implementation

Basic implementation

import 'package:flutter/material.dart';
import 'package:remix/remix.dart';
import 'ui/ui.dart';

class DialogExample extends StatelessWidget {
  const DialogExample({super.key});

  @override
  Widget build(BuildContext context) {
    return FortalButton(
      label: 'Open dialog',
      onPressed: () {
        showRemixDialog(
          context: context,
          builder: (context) => FortalDialog(
            title: 'Revoke access',
            description:
                'This application will no longer be accessible.',
            actions: [
              FortalButton.ghost(
                label: 'Cancel',
                onPressed: () => Navigator.pop(context),
              ),
              FortalButton(
                label: 'Revoke access',
                onPressed: () => Navigator.pop(context),
              ),
            ],
          ),
        );
      },
    );
  }
}

Alert dialogs

Use showRemixAlertDialog for urgent or destructive confirmations. It requires a localized semantic label, keeps barrier dismissal disabled by default, moves focus into the alert, and lets Escape or platform Back cancel safely. A nested RemixDialog automatically reuses the alert semantics wrapper, so no additional configuration is needed.

Destructive alert

import 'package:flutter/material.dart';
import 'package:remix/remix.dart';
import 'ui/ui.dart';

Future<void> showDeleteDialog(BuildContext context) async {
  await showRemixAlertDialog<void>(
    context: context,
    semanticLabel: 'Delete project confirmation',
    builder: (context) => FortalDialog(
      title: 'Delete project?',
      description: 'This permanently deletes the project and all of its data.',
      actions: [
        FortalButton.ghost(
          label: 'Cancel',
          onPressed: () => Navigator.pop(context),
        ),
        FortalButton(
          label: 'Delete project',
          onPressed: () => Navigator.pop(context),
        ),
      ],
    ),
  );
}

Fortal widgets

The application-owned Fortal preset provides a themed widget for this component:

FortalDialog defaults to FortalDialogSize.size3, Alignment.center, fills the available width up to 600 logical pixels, preserves safe viewport insets, and uses modal: true. Set align: Alignment.topCenter to place the surface at the safe top inset.

Fortal widget

import 'package:flutter/material.dart';
import 'ui/ui.dart';

class FortalDialogExample extends StatelessWidget {
  const FortalDialogExample({super.key});

  @override
  Widget build(BuildContext context) {
    return FortalDialog(
      align: Alignment.center,
      title: 'Confirm changes',
      description: 'Save these settings before leaving?',
      actions: [
        FortalButton.ghost(
          label: 'Cancel',
          onPressed: () => Navigator.pop(context),
        ),
        FortalButton(
          label: 'Save',
          onPressed: () => Navigator.pop(context),
        ),
      ],
    );
  }
}

See the fortalDialogStyle source code for all available options.

Show function

showRemixDialog

Future<T?> showRemixDialog<T>({
  required BuildContext context,
  required WidgetBuilder builder,
  Color? barrierColor,
  bool barrierDismissible = true,
  String? barrierLabel,
  bool useRootNavigator = true,
  RouteSettings? routeSettings,
  Offset? anchorPoint,
  Duration transitionDuration = const Duration(milliseconds: 400),
  RouteTransitionsBuilder? transitionBuilder,
  bool requestFocus = true,
  TraversalEdgeBehavior? traversalEdgeBehavior,
})

showRemixAlertDialog

Future<T?> showRemixAlertDialog<T>({
  required BuildContext context,
  required WidgetBuilder builder,
  required String semanticLabel,
  Color? barrierColor,
  String? barrierLabel,
  bool barrierDismissible = false,
  bool useRootNavigator = true,
  RouteSettings? routeSettings,
  Offset? anchorPoint,
  Duration transitionDuration = const Duration(milliseconds: 400),
  RouteTransitionsBuilder? transitionBuilder,
  FocusNode? initialFocusNode,
})

semanticLabel must be a non-empty, localized description of the alert. barrierColor defaults to Colors.black54. If barrierDismissible is enabled, provide a non-empty localized barrierLabel as well.

An initialFocusNode remains owned by the caller and should be attached to a focusable widget inside the alert. If it is omitted, focus uses an autofocus request or the first traversable descendant. Escape and platform Back dismiss the alert with a null result.

Constructor

Constructor

import 'package:flutter/material.dart';
import 'package:remix/remix.dart';

RemixDialog remixDialogConstructor({
  Key? key,
  Widget? child,
  String? title,
  String? description,
  List<Widget>? actions,
  bool modal = true,
  bool scrollable = false,
  String? semanticLabel,
  DialogStyler style = const DialogStyler.create(),
  DialogSpec? styleSpec,
}) => throw UnimplementedError();

Properties

Widget Properties

child -> Widget?

Optional. Custom dialog content rendered after the description and before the actions. When it is the only content provided, it fills the container directly.

title -> String?

Optional. The dialog title text. Either child, title, or description must be provided.

description -> String?

Optional. Supporting body text rendered below the title.

actions -> List<Widget>?

Optional. Action widgets rendered in the dialog actions row.

Optional. Whether the dialog blocks interaction with background content.

scrollable -> bool

Optional. When true, description and child share a vertical scroll region while title and actions remain outside it. A lone child is never wrapped in the scroll region.

semanticLabel → String?

Optional. Accessibility label for the dialog. Defaults to the title when omitted.

style → DialogStyler

Optional. The style configuration for the dialog container, title, description, and actions.

styleSpec → DialogSpec?

Optional. A raw resolved style spec that bypasses fluent style resolution.

Style Methods

container(BoxStyler value)

Configures the dialog container style.

title(TextStyler value)

Configures the title text style.

description(TextStyler value)

Configures the description text style.

actions(FlexBoxStyler value)

Configures the actions row style.

padding(EdgeInsetsGeometryMix value)

Sets dialog container padding.

borderRadius(BorderRadiusGeometryMix radius)

Sets dialog container border radius.

shadow(BoxShadowMix value)

Sets dialog container shadow.

wrap(WidgetModifierConfig value)

Applies widget modifiers such as clipping, opacity, or scaling.

call({Key? key, Widget? child, String? title, String? description, List<Widget>? actions, bool modal = true, String? semanticLabel})

Creates a RemixDialog widget with this style applied.

Alignment API migration

These are source-breaking replacements with no deprecated aliases. Parameter names (alignment, align, and iconAlignment) are unchanged.

Previous APIReplacement
RemixDataListItemAlignment.*CrossAxisAlignment.* (same five values)
RemixDataTableCellAlignment.startAlignmentDirectional.centerStart
RemixDataTableCellAlignment.centerAlignment.center
RemixDataTableCellAlignment.endAlignmentDirectional.centerEnd
FortalDialogAlign.startAlignment.topCenter
FortalDialogAlign.centerAlignment.center
RemixIconAlignment.start/endRemixPlacement.start/end
AgentMessageAlign.start/end (including installed prefixes)RemixPlacement.start/end

Import Flutter alignment types from package:flutter/widgets.dart and shared RemixPlacement from package:remix/remix.dart. Refresh installed dialog and message components with the CLI, preserving any application-owned customizations. The shared placement type is not renamed with the installed component prefix.

Dialog align accepts any AlignmentGeometry, such as Alignment.bottomCenter or AlignmentDirectional.bottomEnd. Directional positions follow RTL; physical positions do not. All positions retain the same safe-area and viewport insets.

View page source on GitHub

On this page