Tangible Design System · @tangible/ui 0.2.29 · Interactive version · Markdown

Modal

import { Modal } from '@tangible/ui';

Interactive docs and examples: Modal in Storybook.

Modal props

Prop Type Default Description
onClose () => void
open boolean
aria-describedby? string Identifies the element (or elements) that describes the object.
aria-labelledby? string Identifies the element (or elements) that labels the current element. ID of the element that labels this dialog. Omitting this leaves the dialog without an accessible name, which violates WCAG 4.1.2 (Name, Role, Value).
children? React.ReactNode
className? string Additional class names applied to the dialog element (.tui-modal__dialog). Use for layout tweaks, custom widths, or context-specific theming.
closeLabel? string 'Close'
closeOnBackdropClick? boolean Close when clicking the backdrop. Default true for role="dialog", false for role="alertdialog" (see role). Passing it explicitly always wins.
closeOnEscape? boolean true
container? Element | null
initialFocusSelector? string
preventScrollOnRestore? boolean false When true, prevents the browser from scrolling to the trigger element when focus is restored on close. Useful when the trigger may be off-screen inside a scrollable container. Default: false.
restoreFocusTo? React.RefObject<HTMLElement | null> | (() => HTMLElement | null) Where focus goes on close, read at close time. Defaults to whatever had focus when the modal opened. Set it when that element can be gone by then: a "Delete" in a list row whose confirm removes the row. Point it at the next row, the list heading or the "Add" button. A function suits a target that only exists by close time (the row after the deleted one). If neither this nor the captured element can take focus, focus falls to and a dev warning names this prop (WCAG 2.4.3).
role? "alertdialog" | "dialog" 'dialog' ARIA role of the dialog element. Default 'dialog'. 'alertdialog' is for a dialog that interrupts the user's workflow to demand a response — a destructive-action confirm is the textbook case. Focus trap, aria-modal, Escape and focus restore behave identically for both roles; what changes is the contract around them: the APG alert dialog pattern expects BOTH aria-labelledby (the heading) and aria-describedby (the message) — a dev warning fires if either is missing — and the backdrop stops dismissing on click unless closeOnBackdropClick says otherwise, since a stray click outside is not a response. Escape still closes: it is the keyboard "cancel". Initial focus lands on the first focusable element in DOM order, skipping the built-in close button (unless initialFocusSelector says otherwise), and the APG wants that to be the safest action — so put Cancel before the destructive action in Modal.Foot. If the visual order must differ (Modal.Foot justify="between" with a destructive action first), point initialFocusSelector at the safe one. https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/
showCloseButton? boolean
size? "lg" | "md" | "sm" | "xl" 'md'
stickyFoot? boolean
stickyHead? boolean

Also accepts the standard attributes of HTMLAttributes (data-*, aria-*, event handlers), passed to the element it renders.

Modal.Head

Prop Type Default Description
children? React.ReactNode
className? string
icon? React.ReactNode Optional icon displayed to the left of the title/subtitle block.
subtitle? React.ReactNode Optional subtitle displayed below the title in smaller, muted text.

Also accepts the standard attributes of HTMLAttributes (data-*, aria-*, event handlers), passed to the element it renders.

Modal.Body

Prop Type Default Description
children? React.ReactNode
className? string
scrollLabel? string Accessible label for the scrollable region. Passed to the inner scroll container. When the body content overflows, screen readers announce this as the region name. Omitting this on a scrollable modal body leaves the scroll region unlabelled.

Also accepts the standard attributes of HTMLAttributes (data-*, aria-*, event handlers), passed to the element it renders.

Modal.Foot

Prop Type Default Description
children? React.ReactNode
className? string
justify? "between" | "end" | "start" 'end' How the actions distribute along the row. 'end' (default) keeps them together at the inline end, so reading order is visual order and the primary action comes last; 'start' keeps them together at the inline start; 'between' separates the first action from the rest, which stay grouped at the end — the place for a destructive or tertiary action you want visibly apart from the primary. Visual order follows DOM order, and so does the dialog's initial focus: a destructive action placed first will be focused first unless the Modal's initialFocusSelector points at a safer one. Published as data-justify on .tui-modal__foot.

Also accepts the standard attributes of HTMLAttributes (data-*, aria-*, event handlers), passed to the element it renders.

Modal.Close

Prop Type Default Description
className? string
label? string 'Close'

Examples

Component API tokens

Read via fallback, never declared. Set one on an ancestor to restyle every instance under it.