Dialog

Material Design 3 dialog component using native HTML dialog element for accessible modal interactions

Dialog

Dialogs inform users about a task and can contain critical information, require decisions, or involve multiple tasks. @duskmoon-dev/core provides Material Design 3 dialog styles built on the native HTML <dialog> element for excellent accessibility and built-in functionality.

Why Native Dialog?

The native <dialog> element provides:

  • Built-in accessibility - Focus trapping, Escape key handling, and ARIA attributes
  • Native backdrop - Via ::backdrop pseudo-element
  • Modal behavior - showModal() method handles overlay and focus
  • Browser-native - No JavaScript required for basic functionality

Basic Usage

A basic dialog consists of a <dialog> element with inner structure for header, body, and footer.

Basic Dialog

Dialog Title

This is the dialog content. You can add any content here.

Size Variants

Small Dialog

Perfect for simple confirmations and alerts.

Small Dialog

Small Dialog

This is a small dialog (max-width: 20rem).

Large Dialog

For dialogs with more content.

Large Dialog

Large Dialog

This is a large dialog (max-width: 40rem). It provides more space for complex content like forms, tables, or detailed information.

Extra Large Dialog

For complex forms or detailed content.

Extra Large Dialog

Extra Large Dialog

This is an extra large dialog (max-width: 56rem). Use it for complex workflows, data tables, or multi-step forms.

Fullscreen Dialog

Covers the entire viewport, ideal for mobile experiences or immersive content.

Fullscreen Dialog

Fullscreen Dialog

This dialog covers the entire screen with no border radius. Perfect for mobile experiences or content that needs maximum space.

Dialog Variants

Alert Dialog

Simplified dialog for confirmations and critical actions.

Alert Dialog

Delete Item?

Are you sure you want to delete this item? This action cannot be undone.

Dialog with Dividers

Add visual separation between sections using the dialog-divider class.

Dialog with Dividers

Settings

The header and footer have visible divider lines for clear section separation.

Right-Aligned (Default)

Right-Aligned Footer

Right-Aligned Actions

Footer actions are right-aligned by default.

Left-Aligned Footer

Left-Aligned Actions

Use dialog-footer-start for left-aligned actions.

Center-Aligned Footer

Center-Aligned Actions

Use dialog-footer-center for centered actions.

Space-Between Footer

Space-Between Actions

Use dialog-footer-between to space actions apart.

Scrollable Dialog

For dialogs with long content, add the dialog-scrollable class:

Scrollable Dialog

Terms and Conditions

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis.

Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.

Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore.

Position Variants

Top Position

Top Positioned Dialog

Top Dialog

This dialog appears at the top of the viewport.

Bottom Position

Bottom Positioned Dialog

Bottom Dialog

This dialog appears at the bottom of the viewport.

JavaScript Integration

The native <dialog> element provides built-in methods:

// Get dialog reference
const dialog = document.querySelector('dialog');

// Open as modal (with backdrop)
dialog.showModal();

// Open as non-modal (no backdrop)
dialog.show();

// Close dialog
dialog.close();

// Check if open
if (dialog.open) {
  console.log('Dialog is open');
}

// Listen for close event
dialog.addEventListener('close', () => {
  console.log('Dialog was closed');
});

// Close on backdrop click
dialog.addEventListener('click', (e) => {
  if (e.target === dialog) {
    dialog.close();
  }
});

Complete Example

JavaScript Integration Example

Interactive Dialog

This dialog uses JavaScript for all interactions.

Framework Examples

React

import { useRef } from 'react';

interface DialogProps {
  title: string;
  children: React.ReactNode;
  onClose?: () => void;
}

export function Dialog({ title, children, onClose }: DialogProps) {
  const dialogRef = useRef<HTMLDialogElement>(null);

  const openDialog = () => dialogRef.current?.showModal();
  const closeDialog = () => {
    dialogRef.current?.close();
    onClose?.();
  };

  return (
    <>
      <button className="btn btn-primary" onClick={openDialog}>
        Open Dialog
      </button>
      <dialog
        ref={dialogRef}
        className="dialog"
        onClick={(e) => e.target === e.currentTarget && closeDialog()}
      >
        <div className="dialog-box">
          <div className="dialog-header">
            <h2 className="dialog-title">{title}</h2>
            <button className="dialog-close" onClick={closeDialog} aria-label="Close">
              ร—
            </button>
          </div>
          <div className="dialog-body">{children}</div>
          <div className="dialog-footer">
            <button className="btn btn-ghost" onClick={closeDialog}>Cancel</button>
            <button className="btn btn-primary" onClick={closeDialog}>Confirm</button>
          </div>
        </div>
      </dialog>
    </>
  );
}

Vue

<template>
  <button class="btn btn-primary" @click="openDialog">Open Dialog</button>
  <dialog ref="dialogRef" class="dialog" @click.self="closeDialog">
    <div class="dialog-box">
      <div class="dialog-header">
        <h2 class="dialog-title">{{ title }}</h2>
        <button class="dialog-close" @click="closeDialog" aria-label="Close">ร—</button>
      </div>
      <div class="dialog-body">
        <slot />
      </div>
      <div class="dialog-footer">
        <button class="btn btn-ghost" @click="closeDialog">Cancel</button>
        <button class="btn btn-primary" @click="closeDialog">Confirm</button>
      </div>
    </div>
  </dialog>
</template>

<script setup>
import { ref } from 'vue';

defineProps({ title: String });

const dialogRef = ref(null);
const openDialog = () => dialogRef.value?.showModal();
const closeDialog = () => dialogRef.value?.close();
</script>

Best Practices

Accessibility

The native <dialog> element handles most accessibility concerns automatically:

  • Focus trapping - Focus is trapped within the modal when open
  • Escape key - Pressing Escape closes the dialog
  • Focus restoration - Focus returns to the trigger element when closed
  • ARIA attributes - The dialog has implicit role="dialog" and aria-modal="true"

Add descriptive labels for additional accessibility:

<dialog class="dialog" aria-labelledby="dialogTitle" aria-describedby="dialogDesc">
  <div class="dialog-box">
    <div class="dialog-header">
      <h2 class="dialog-title" id="dialogTitle">Confirm Action</h2>
    </div>
    <div class="dialog-body">
      <p id="dialogDesc">Are you sure you want to proceed?</p>
    </div>
  </div>
</dialog>

User Experience

  1. Use dialogs sparingly - Donโ€™t interrupt the user unnecessarily
  2. Keep content focused - Present one task or decision at a time
  3. Provide clear actions - Use descriptive button labels
  4. Enable easy dismissal - The native dialog supports Escape key and backdrop clicks
  5. Consider mobile - Use fullscreen variant on small screens

API Reference

Class Names

ClassDescription
.dialogBase dialog styles (apply to <dialog> element)
.dialog-boxInner container for flex layout
.dialog-headerHeader section with title and close button
.dialog-titleDialog title text
.dialog-closeClose button in header
.dialog-bodyContent section
.dialog-footerFooter with action buttons
.dialog-smSmall dialog (max-width: 20rem)
.dialog-lgLarge dialog (max-width: 40rem)
.dialog-xlExtra large dialog (max-width: 56rem)
.dialog-fullscreenFullscreen dialog
.dialog-topPosition at top of viewport
.dialog-bottomPosition at bottom of viewport
.dialog-scrollableEnable body scrolling (max-height: 50vh)
.dialog-dividerAdd dividers to header and footer
.dialog-footer-startLeft-align footer actions
.dialog-footer-centerCenter-align footer actions
.dialog-footer-betweenSpace-between footer actions

Native Dialog Methods

MethodDescription
showModal()Open dialog as modal with backdrop
show()Open dialog without backdrop
close()Close the dialog

Native Dialog Properties

PropertyDescription
openBoolean indicating if dialog is open
returnValueString value passed to close()
  • Button - Dialog action buttons
  • Card - Similar container component
  • Alert - For inline notifications

See Also