Components · Feedback & status

Dialog

The only component permitted to take the screen away from a clinician. That power is why it is rare, why it is small, and why almost every request for one is better served by something else.

Stable · v1.0 shadcn/ui Radix Dialog WCAG 2.2 AA

Overview

A dialog interrupts. It steals focus, traps the keyboard, dims the record behind it and refuses to go away until answered. In consumer software that is a mild annoyance. In clinical software it is a deliberate decision to stand between a clinician and a patient's data.

So the bar is high: a dialog is justified only when continuing without a decision would be worse than the interruption. Everything else — status, findings, confirmations, errors — belongs in an Alert Banner, inline, or in a popover.

Rare

Every dialog spends the clinician's attention and the product's credibility. If two appear in one workflow, the workflow is wrong, not under-dialogued.

Self-contained

Everything needed to answer is inside it. A dialog that asks a question whose answer is hidden behind it forces a guess.

Never over an alarm

No dialog may obscure an active Critical or Urgent alarm. The interruption is always subordinate to the patient signal.

When to use

Use a DialogUse something else
An irreversible action needs confirmation — discarding a draft report A reversible action → act immediately, offer undo
A decision must be made before the workflow can continue — claiming or discarding another clinician's draft Information the clinician should see but need not answer → Alert Banner
A short, focused input is needed out of context — a reason for emergency access A form of more than about six fields → its own screen
An identity or context boundary is being crossed — switching user A finding, however serious → Alert Banner. Alarms are not dialogs.
An alarm is never a dialog

It is tempting to make a STEMI detection a modal — it feels proportionate to the urgency. It is the wrong call. A modal alarm blocks the very screens the clinician needs to assess it, can only show one alarm at a time, and trains a reflex of dismissing modals fast. Alarms are persistent banners that can be read, ranked and acted on alongside the evidence. See Alert Banner.

Anatomy

Destructive confirmation
ElementRule
Title A question or a statement of the decision. Names the object — "Discard this draft report?", never "Are you sure?"
Description What will happen, and to whom. Includes the patient identifier when the action is patient-scoped, because the header may be obscured.
Actions Two, occasionally three. Each label names its outcome. Confirming action last, on the right; cancel first.
Scrim Dims but never hides. The record behind stays legible enough to read an identifier.
Close affordance Present only where dismissal is a safe default. Omitted where a decision is genuinely required.

Variants

confirm

Two actions, cancel and proceed. The default.

decide

No safe default exists, so there is no cancel and no close affordance — both options are real choices. Used sparingly; the identity-boundary case from Sign in / sign out is the canonical one.

variant: decide · no safe default

input

A short focused form — at most about six fields. Anything larger is a screen, not a dialog, because a long form inside a modal cannot be cross-referenced against the record behind it.

variant: input · emergency access reason
Access first, reason second

Note the ordering in that example: access is already granted when the dialog appears. A break-glass prompt that gates entry on typing a justification is a dialog standing between a clinician and a patient in an emergency. Capture the reason; never charge admission for it.

Behaviour

Critical alarm arriving over an open dialog

Writing the dialog

Do
Discard this draft report?
Your interpretation for HARLAND, A. · MRN 44 812 907 will be permanently lost. The ECG is unaffected.

Object named, patient restated, scope of loss bounded, labels readable out of context.

Don't
Are you sure?
This action cannot be undone.

Sure about what, for whom, losing what? The destructive action is styled as primary and focused by default.

Do's and don'ts

Do
Discard this draft report?
Your interpretation for HARLAND, A. · MRN 44 812 907 will be permanently lost.

Initial focus on the safe option. Pressing Enter reflexively loses nothing.

Don't
Discard this draft report?
Your interpretation will be permanently lost.

Focus on the destructive action, and no patient named. Enter deletes the report.

Do
STEMI pattern detected — OKONKWO, B.
renders above the scrim
Switch user?
S. Whitfield's session will be locked.

The alarm renders above the scrim and stays readable. The dialog waits its turn.

Don't
Switch user?
S. Whitfield's session will be locked.

A modal over everything. A STEMI has just fired for another patient and nothing on screen says so.

Accessibility

Outcomes of use

What this contributes to, in the terms of Usability & context of use. These are attributes believed to contribute to an outcome; the outcome itself is settled by observing real use in a specified context, not by this page.

Clinical safety notes

Risk controls carried by this component

Trace these in your risk file (ISO 14971) and usability engineering file (IEC 62366-1).

Implementation

$ npx shadcn@latest add https://md.notjustany.tech/r/dialog.json
import {
  Dialog, DialogContent, DialogHeader, DialogTitle,
  DialogDescription, DialogFooter,
} from "@/components/ui/dialog"

<Dialog open={open} onOpenChange={setOpen}>
  <DialogContent
    variant="confirm"
    // destructive confirms cannot be dismissed by accident
    onEscapeKeyDown={(e) => e.preventDefault()}
    onPointerDownOutside={(e) => e.preventDefault()}
  >
    <DialogHeader>
      <DialogTitle>Discard this draft report?</DialogTitle>
      <DialogDescription>
        Your interpretation for {patient.display} · MRN {patient.mrn} will be
        permanently lost. The original ECG and the model finding are unaffected.
      </DialogDescription>
    </DialogHeader>
    <DialogFooter>
      // autoFocus on the safe option, never the destructive one
      <Button variant="outline" size="lg" autoFocus>Keep editing</Button>
      <Button variant="destructive" size="lg" onClick={discard}>
        Discard draft report
      </Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

Props

PropTypeDefaultNotes
variantconfirm | decide | input confirm decide removes the close affordance and disables Escape.
subjectIdstring Required for patient-scoped actions; rendered into the description.
onEscapeKeyDown(e) => voidcloses Prevent for destructive confirms.
onPointerDownOutside(e) => voidcloses Prevent for destructive confirms.
Lint rule

A dialog rendered with priority or any --alarm-* token in its subtree fails the build. Alarms are banners; this is enforced rather than documented, for the same reason the alarm tokens are governed.

NotJustAnyMed.Tech Design System · Dialog · v1.0 · draft for review
Reference applications named in this system are fictional; all patient data shown is fabricated.