MD3
Expressive
MATERIAL DESIGN 3 EXPRESSIVE

Dialogs

Dialogs provide important prompts in a user flow. They inform users about critical information, require decisions, or involve multiple tasks.

Dialogs focus user attention exclusively on one task or a piece of information via a modal overlay. Expressive dialogs use spring-based motion for entrance/exit animations and clear typography hierarchy.

Introduction

The MD3 Expressive Dialog is a versatile modal component that ranges from simple confirmation alerts to complex full-screen forms. It leverages Radix UI for robust accessibility and Framer Motion for premium, critically-damped spring animations that make the UI feel alive and responsive.

Anatomy

  • Scrim (Overlay): A semi-transparent background that dims the underlying UI.

  • Container: The panel holding the content. Uses rounded corners (28dp) to match the MD3 expressive language.

  • Icon (Optional): A visual indicator placed at the top for emphasis (e.g., Warning, Success).

  • Title: A clear, concise heading describing the purpose.

  • Description / Body: The main content area, which can be scrollable.

  • Footer / Actions: Buttons for the user to confirm or dismiss the prompt.

Variants

Basic Dialog

A standard modal for simple messages or confirmations.

Loading demo...

Icon Dialog

Adds an icon at the top for additional context and visual weight.

Loading demo...

Full-screen Dialog

Covers the entire viewport. Best for complex mobile-first tasks like creating a new record or extensive form filling.

Loading demo...

Features

Scrollable Body

Use DialogBody to create a scrollable region while keeping the title and footer sticky.

Loading demo...

Expressive Motion

Dialogs use a spring animation that feels "emphasized" and tactile, transitioning smoothly from a slightly scaled-down state to full size.

Usage

Basic Usage

import {
  Dialog,
  DialogTrigger,
  DialogPortal,
  DialogOverlay,
  DialogContent,
  DialogTitle,
  DialogDescription,
  DialogFooter,
  Button
} from "@bug-on/m3-expressive";

export function Example() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>Open Dialog</Button>
      </DialogTrigger>
      <DialogPortal>
        <DialogOverlay />
        <DialogContent>
          <DialogTitle>Confirm Action</DialogTitle>
          <DialogDescription>
            Are you sure you want to proceed with this operation?
          </DialogDescription>
          <DialogFooter>
            <Button colorStyle="text">Cancel</Button>
            <Button>Confirm</Button>
          </DialogFooter>
        </DialogContent>
      </DialogPortal>
    </Dialog>
  );
}

Best Practices

Do

  • Use Dialogs for critical information that requires a decision.
  • Keep the title concise and the description focused.
  • Use Full-screen dialogs for complex tasks on mobile devices.
  • Ensure the primary action is clear (e.g., using a high-emphasis button).

Don't

  • Don't use a Dialog for information that is already visible on the main screen.
  • Don't use too many Dialogs in a single user flow; it can be disruptive.
  • Avoid long-running tasks inside a Dialog unless you provide a clear progress indicator.

Accessibility

  • Keyboard: Tab cycles focus inside the dialog. Esc closes the dialog.
  • Roles: Uses role="dialog" or role="alertdialog" depending on content.
  • Linking: Automatically links DialogTitle and DialogDescription via ARIA attributes.
  • Restoration: Focus is restored to the trigger element when the dialog closes.

API Reference

Dialog

Root component.

PropTypeDefaultDescription
openbooleanControlled open state.
onOpenChange(open: boolean) => voidOpen state change callback.

DialogContent

The main container.

PropTypeDefaultDescription
asChildbooleanfalseRenders as the child element.
classNamestringCustom classes.

DialogFullScreenContent

PropTypeDefaultDescription
titlestringRequired. Header title.
actionLabelstringLabel for primary action.
onAction() => voidPrimary action callback.