Skip to main content

Modal

packages/core/components/molecules/Modal.js · Tier: molecule · Module: core · Rendering: Client Component ('use client')

Purpose​

The accessible modal dialog base, backed by @radix-ui/react-dialog. It provides, out of the box, a focus trap, ESC-to-close, return-focus on close, scroll lock, backdrop click and full ARIA wiring (role="dialog", aria-modal="true", aria-labelledby). Callers control visibility via { open, onClose }.

Props​

PropTypeRequiredDefaultDescription
openbooleanyes—Visibility (Radix Dialog.Root open).
onClose() => voidyes—Called when the dialog requests to close.
titlestringyes—Dialog title (Dialog.Title).
descriptionstringno—Optional description; when omitted, the title is used as a visually-hidden description.
closeLabelstringnodict.a11y.closeDialogAccessible label for the close button.
panelClassNamestringnow-[min(32rem,…)]Overrides the panel width/size.
bodyClassNamestringnopx-lg py-md flex-1Overrides the body wrapper classes.
childrenReactNodeyes—Dialog body.

Composition​

  • Uses: @radix-ui/react-dialog, atoms/core/Icon (close), atoms/core/VisuallyHidden, useTranslations().
  • Used by: every modal molecule/organism (SessionExpiredModal, SettingsModal, CreateAgentModal, AddCarModal, RenewStayModal, SanctionDetailModal, EditQuestionModal, …).

Internationalisation​

Reads dict.a11y.closeDialog (fallback 'Close dialog') for the close button.

Accessibility​

Implements WCAG 2.2 SC 2.1.1 (Keyboard), 2.1.2 (No Keyboard Trap), 2.4.3 (Focus Order), 2.4.7 (Focus Visible) and 4.1.2 (Name/Role/Value) via Radix. When no description is given, a VisuallyHidden description is emitted to satisfy the dialog contract.

Styling & tokens​

bg-surface, border-outline-variant, rounded-md, shadow-xl, overlay bg-black/50 backdrop-blur-sm, max-h-[90vh].

Usage​

<Modal open={open} onClose={close} title={t.dialog.title} description={t.dialog.desc}>
{/* body */}
</Modal>

molecules/core/SessionExpiredModal, molecules/core/SettingsModal, molecules/core/CreateAgentModal.