Dialog

Dialog

The Dialog component displays content in a modal overlay. It can be used for confirmations, forms, alerts, and other interactions that require the user’s attention before returning to the underlying page.

import { createEffect, createSignal } from "solid-js";
import Button from "rocksolidjs/Button";
import Dialog from "rocksolidjs/Dialog";
import DialogActions from "rocksolidjs/DialogActions";
import DialogContent from "rocksolidjs/DialogContent";
import DialogTitle from "rocksolidjs/DialogTitle";

export default function Example() {
  const [open, setOpen] = createSignal(false);

  let openButton!: HTMLButtonElement, 
      closeBtn!: HTMLButtonElement;

  createEffect(() => {
    if (open()) {
      closeBtn.focus();
    }
  });

  const handleDialogClose = () => {
    setOpen(false);
    openButton.focus();
  };

  return (
    <>
      <Button
        ref={openButton}
        onClick={() => setOpen(true)}
      >
        Open dialog
      </Button>

      <Dialog
        open={open()}
        aria-labelledby="getting-started-dialog-title"
        onClose={handleDialogClose}
        class="max-w-md"
      >
        <DialogTitle id="getting-started-dialog-title">
          Getting Started
        </DialogTitle>
        <DialogContent>
          Complete the setup to access all available features.
        </DialogContent>
        <DialogActions>
          <Button
            ref={closeBtn}
            onClick={handleDialogClose}
          >
            Close
          </Button>
        </DialogActions>
      </Dialog>
    </>
  );
}

Examples

Open

Use the open prop to control whether the dialog is visible. Place the interactive content inside the dialog and use DialogActions for actions such as canceling or confirming an operation.

import { createEffect, createSignal } from "solid-js";
import Button from "rocksolidjs/Button";
import Dialog from "rocksolidjs/Dialog";
import DialogActions from "rocksolidjs/DialogActions";
import DialogContent from "rocksolidjs/DialogContent";
import DialogTitle from "rocksolidjs/DialogTitle";

export default function Example() {
  const [open, setOpen] = createSignal(false);

  let openButton!: HTMLButtonElement, 
      closeBtn!: HTMLButtonElement;

  createEffect(() => {
    if (open()) {
      closeBtn.focus();
    }
  });

  const handleDialogClose = () => {
    setOpen(false);
    openButton.focus();
  };

  return (
    <>
      <Button
        ref={openButton}
        onClick={() => setOpen(true)}
      >
        Open dialog
      </Button>

      <Dialog
        open={open()}
        aria-labelledby="welcome-dialog-title"
        onClose={handleDialogClose}
        class="max-w-md"
      >
        <DialogTitle id="welcome-dialog-title">
          Welcome to the workspace
        </DialogTitle>
        <DialogContent>
          Your workspace is ready. You can invite your team, create
          projects, and start collaborating.
        </DialogContent>
        <DialogActions>
          <Button
            ref={closeBtn}
            onClick={handleDialogClose}
          >
            Close
          </Button>
        </DialogActions>
      </Dialog>
    </>
  );
}

Alert dialog

Use role="alertdialog" for dialogs that require the user’s immediate attention, such as destructive or irreversible actions. Use aria-labelledby to associate the dialog with its DialogTitle.

import { createSignal, createEffect } from "solid-js";
import Button from "rocksolidjs/Button";
import Dialog from "rocksolidjs/Dialog";
import DialogActions from "rocksolidjs/DialogActions";
import DialogContent from "rocksolidjs/DialogContent";
import DialogTitle from "rocksolidjs/DialogTitle";

export default function Example() {
  const [open, setOpen] = createSignal(false);

  let openButton!: HTMLButtonElement, 
      cancelBtn!: HTMLButtonElement;
  
  createEffect(() => {
    if (open()) {
      cancelBtn.focus();
    }
  });

  const handleDialogClose = () => {
    setOpen(false);
    openButton.focus();
  };

  return (
    <>
      <Button
        ref={openButton}
        onClick={() => setOpen(true)}
      >
          Delete account
      </Button>

      <Dialog
        open={open()}
        role="alertdialog"
        aria-labelledby="delete-account-title"
        onClose={handleDialogClose}
        class="max-w-md"
      >
        <DialogTitle id="delete-account-title">
          Delete account?
        </DialogTitle>
        <DialogContent>
          This action permanently deletes your account and all of its data.
          You won't be able to undo this action.
        </DialogContent>
        <DialogActions>
          <Button
            ref={cancelBtn}
            variant="outlined"
            onClick={handleDialogClose}
          >
            Cancel
          </Button>
          <Button
            color="error"
            onClick={handleDialogClose}
          >
            Delete account
          </Button>
        </DialogActions>
      </Dialog>
    </>
  );
}

Fullscreen

Use the fullscreen prop when the dialog should occupy the available viewport instead of appearing as a smaller modal.

import { createSignal } from "solid-js";
import Button from "rocksolidjs/Button";
import Dialog from "rocksolidjs/Dialog";
import DialogActions from "rocksolidjs/DialogActions";
import DialogContent from "rocksolidjs/DialogContent";
import DialogTitle from "rocksolidjs/DialogTitle";

export default function Example() {
  const [open, setOpen] = createSignal(false);

  return (
    <>
      <Button onClick={() => setOpen(true)}>View report</Button>

      <Dialog
        open={open()}
        fullscreen
        onClose={() => setOpen(false)}
      >
        <DialogTitle>Quarterly sales report</DialogTitle>
        <DialogContent>
          <p>
            Review your sales performance for the current quarter.
          </p>
          <ul>
            <li>Revenue increased by 18%.</li>
            <li>New customers increased by 24%.</li>
            <li>Customer retention improved by 6%.</li>
          </ul>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setOpen(false)}>Close</Button>
        </DialogActions>
      </Dialog>
    </>
  );
}

Close Reasons

Use the onClose callback to respond when the dialog is requested to close. The callback receives the event and a reason describing how the close was triggered.

The reason can be one of:

  • escape — The user pressed the Escape key.
  • backdrop — The user interacted with the backdrop.
import { createSignal } from "solid-js";
import Button from "rocksolidjs/Button";
import Dialog, { type DialogCloseReason } from "rocksolidjs/Dialog";
import DialogActions from "rocksolidjs/DialogActions";
import DialogContent from "rocksolidjs/DialogContent";
import DialogTitle from "rocksolidjs/DialogTitle";
import Typography from "rocksolidjs/Typography";

export default function Example() {
  const [open, setOpen] = createSignal(false);
  const [reason, setReason] = createSignal<string>();

  const handleClose = (
    _event: Event,
    closeReason: DialogCloseReason,
  ) => {
    setReason(closeReason);
    setOpen(false);
  };

  return (
    <div class="space-y-2 text-center">
      <Button
        onClick={() => setOpen(true)}
      >
        Open dialog
      </Button>

      {reason() && (
        <Typography>
          Dialog closed because of: <strong>{reason()}</strong>
        </Typography>
      )}

      <Dialog
        open={open()}
        onClose={handleClose}
      >
        <DialogTitle>Unsaved changes</DialogTitle>
        <DialogContent>
          You have changes that haven't been saved. Are you sure you want to
          leave this dialog?
        </DialogContent>
        <DialogActions>
          <Button
            onClick={() => setOpen(false)}
          >
            Keep editing
          </Button>
          <Button
            onClick={() => setOpen(false)}
            color="error"
          >
            Discard changes
          </Button>
        </DialogActions>
      </Dialog>
    </div>
  );
}

Customization

Use the class prop on each Dialog component to add custom styling.

import { createSignal } from "solid-js";
import Button from "rocksolidjs/Button";
import Dialog from "rocksolidjs/Dialog";
import DialogActions from "rocksolidjs/DialogActions";
import DialogContent from "rocksolidjs/DialogContent";
import DialogTitle from "rocksolidjs/DialogTitle";
import Divider from "rocksolidjs/Divider";

export default function Example() {
  const [open, setOpen] = createSignal(false);

  return (
    <>
      <Button onClick={() => setOpen(true)}>Show alert</Button>

      <Dialog
        open={open()}
        class="max-w-xs rounded-2xl"
        aria-labelledby="ios-dialog-title"
        onClose={() => setOpen(false)}
      >
        <DialogTitle
          id="ios-dialog-title"
          class="text-center"
        >
          Allow Notifications?
        </DialogTitle>
        <DialogContent class="px-6 pb-5 text-center text-balance">
            Notifications may include alerts, sounds, and icon badges.
        </DialogContent>
        <DialogActions class="flex gap-2">
          <Button
            variant="text"
            class="flex-1"
            onClick={() => setOpen(false)}
          >
            Don't Allow
          </Button>
          <Divider
            orientation="vertical" 
          />
          <Button
            variant="text"
            class="font-semibold flex-1"
            onClick={() => setOpen(false)}
          >
            Allow
          </Button>
        </DialogActions>
      </Dialog>
    </>
  );
}

Accessibility

  • The dialog uses role="dialog" by default. Use role="alertdialog" when the dialog requires the user’s immediate attention, such as a destructive confirmation.
  • The dialog should use aria-labelledby to reference the DialogTitle, providing an accessible name for the dialog.
  • The dialog uses aria-modal="true" to indicate that content outside the dialog is not available while it is open.
  • When the dialog opens, ensure focus is moved to an appropriate element based on the dialog’s purpose and interaction requirements.
  • When the dialog closes, focus should be restored to the element that triggered it.
  • The Dialog component automatically traps focus within the dialog while it is open.
  • Give every dialog a clear and descriptive DialogTitle.
  • Ensure the dialog can be closed using the Escape key when appropriate.
  • Use clear labels for actions, especially for destructive or irreversible operations.
  • When using a close button, ensure it has an accessible name.

API

Dialog

The Dialog component controls the modal container and provides support for controlled visibility, fullscreen layouts, custom styling, and close events.

Prop Type Required Default Description
aria-labelledby string No Identifies the element that labels the dialog, typically the DialogTitle element.
children JSXElement No Content rendered inside the dialog.
class string No Custom CSS class applied to the dialog.
fullscreen boolean No false Controls whether the dialog is displayed in fullscreen mode.
open boolean No Controls whether the dialog is open.
onClose (event: Event, reason: DialogCloseReason) => void No Callback invoked when the dialog requests to close. The reason identifies how the close was triggered: escape when the user presses the Escape key, or backdrop when the user clicks the backdrop.
role "dialog" | "alertdialog" No "dialog" Defines the semantic role of the dialog. Use alertdialog when the dialog requires the user’s immediate attention.
slotProps { backdrop?: object } No Provides additional props for customizing individual dialog slots.
  • backdrop — Props for customizing the dialog backdrop.

DialogTitle

DialogTitle provides the heading for a dialog.

Prop Type Required Default Description
children JSXElement No Content rendered as the dialog title.
class string No Custom CSS class applied to the dialog title.

DialogContent

DialogContent contains the primary content of the dialog.

Prop Type Required Default Description
children JSXElement No Content rendered inside the dialog body.
class string No Custom CSS class applied to the dialog content.

DialogActions

DialogActions contains actions such as buttons, links, or other controls that appear at the bottom of the dialog.

Prop Type Required Default Description
children JSXElement No Action elements rendered inside the dialog actions container.
class string No Custom CSS class applied to the dialog actions container.
  • Alert — Use Alert for important messages that do not require modal interaction.
  • Button — Use Button for actions inside DialogActions.