Modal
Carbon Design System — Modal
Overview
Modals focus user attention on a single task or message by placing content over the main UI with a blocking overlay. Use for confirmations, forms requiring separate context, or critical alerts. Avoid modals for simple messages that could be inline or toasted.
Carbon Modal corresponds to the web ARIA pattern role="dialog".
Variants
Passive modal
- No action buttons in the footer
- Used for informational content; dismissed by close icon or Esc key
- Example: "Your session will expire in 5 minutes"
Transactional modal
- Has primary + secondary buttons in footer
- Not dismissible by clicking outside (by default) — user must take an action
- Used for: form submission, confirming a choice, save/discard prompts
Danger modal
- Same as transactional, but the primary action button uses
dangerkind - Use for irreversible destructive actions: delete account, purge data, disconnect service
- Red danger button (right) + cancel button (left)
Acknowledgment modal
- Single button only (typically "OK" or "Got it")
- Used when the user must acknowledge something before continuing
Sizes
| Size | Max-width |
|---|---|
xs | 448px |
sm | 592px |
md (default) | 768px |
lg | 1024px |
Choose based on content volume. Forms typically use sm or md; detailed reference content may use lg.
Anatomy
ModalHeader
<ModalHeader label="Optional context" title="Modal heading" />
- Label (optional) — small text above the heading; provides context (e.g., "Account settings")
- Title — main heading; concise and action-oriented
- Close button —
Xicon in top-right corner; always present
ModalBody
<ModalBody hasForm hasScrollingContent>
{/* content */}
</ModalBody>
hasForm— removes default padding so form elements align correctlyhasScrollingContent— adds a fade gradient at the bottom to indicate overflow
ModalFooter
<ModalFooter
primaryButtonText="Save"
secondaryButtonText="Cancel"
onRequestSubmit={handleSave}
onRequestClose={handleClose}
/>
- Secondary (cancel) button on the left
- Primary (confirm) button on the right
- Danger modal: use
dangerprop on Modal (automatically styles primary button as danger)
Focus management
On open, focus moves to the first interactive element inside the modal. If a specific element should receive focus, add data-modal-primary-focus to it, or use the selectorPrimaryFocus prop.
<Modal selectorPrimaryFocus="[data-modal-primary-focus]">
<ModalBody>
<TextInput data-modal-primary-focus labelText="Name" />
</ModalBody>
</Modal>
Tab cycling stays within the modal — focus does not escape to the page behind.
Behavior
<Modal
open={isOpen}
onRequestClose={handleClose}
onRequestSubmit={handleSubmit}
preventCloseOnClickOutside /* for transactional modals */
modalHeading="Delete workspace"
danger
>
<ModalBody>
<p>This action cannot be undone.</p>
</ModalBody>
<ModalFooter
primaryButtonText="Delete"
secondaryButtonText="Cancel"
/>
</Modal>
opencontrols visibilitypreventCloseOnClickOutside— set for transactional/danger modals; users must interact with the buttonsonRequestClosefires on close icon click, Esc key, or (if enabled) outside click- Modal renders into a portal at the document body — no z-index conflicts
Floating menus inside modals
If the modal contains dropdowns, date pickers, or tooltips, pass their selector to selectorsFloatingMenus so they don't trap focus incorrectly:
<Modal selectorsFloatingMenus=".cds--date-picker__calendar">
Accessibility
role="dialog",aria-modal="true"aria-labelledbypointing toModalHeadertitle- Focus trap: keyboard navigation stays within modal bounds
- Return focus to trigger element on close
- Esc key closes passive modals; for transactional, Esc fires
onRequestClose(which may be a no-op) - Screen reader announcement: modal heading is read when dialog opens