Overlays@knitui/components
Modal
Modal is an overlay dialog composed of Modal.Content, Modal.Header, Modal.Title, Modal.Body, and Modal.CloseButton. Pass opened and onClose to control visibility. size sets the content width, centered vertically centres the panel, and fullScreen expands it to fill the viewport. padding tunes the inner spacing, withHeaderDivider separates a pinned header from a scrolling body, and closeButtonProps fully customises the close control. Behaviour knobs (closeOnEscape, closeOnClickOutside, lockScroll, trapFocus, returnFocus, keepMounted) mirror Mantine. The body scrolls automatically when its content is taller than the viewport while the header stays pinned.
import { Modal } from "@knitui/components";Playground
Loading playground…
<Modal
opened={false}
title="Modal title"
size="md"
shadow="xl"
centered={false}
fullScreen={false}
withCloseButton
withHeaderDivider={false}
withOverlay
>
Modal body content goes here.
</Modal>Examples
Trigger
A controlled trigger — press the button to open, close button or backdrop to dismiss.
Loading example…
Sizes
All seven content widths shown via a controlled trigger for each size.
Loading example…
Shadows
Each shadow elevation step (xxs–xxl) on the content panel.
Loading example…
Centered
Vertically centred in the viewport — useful for confirmation dialogs.
Loading example…
Full Screen
Full-screen mode — no radius, no padding offset, fills the entire viewport.
Loading example…
Without Close Button
Close button hidden — the caller is responsible for dismissal.
Loading example…
Custom Close Label
Custom aria-label on the close button for screen-reader users.
Loading example…
Scrollable Body
Long content scrolls inside the body while the header stays pinned.
Loading example…
Compound API
Compound API — compose Modal.Header, Modal.Title, and Modal.Body directly.
Loading example…
Styles
Per-slot styles targets individual parts — here the overlay, content, and title.
Loading example…
With Header Divider
A hairline divider separates the pinned header from a scrolling body.
Loading example…
Custom Padding
Roomier padding on the header and body for a more spacious layout.
Loading example…
Custom Close Button
The close control is fully customisable via closeButtonProps — here a larger, rounded button.
Loading example…
No Overlay
No backdrop — the modal floats over the page without dimming it.
Loading example…
Non Dismissable
A non-dismissable dialog — escape and backdrop clicks are disabled; only an explicit action closes it.
Loading example…
With Rich Content
Rich body content — a confirmation dialog with actions.
Loading example…
Drag To Dismiss
Drag-to-dismiss (dragToDismiss) — flick the panel up to close it, the same reanimated + gesture mechanic as @knitui/sheet. The CSS enter/exit motion is unchanged; this only adds the interactive drag. Release past ~30% of the panel height (or an upward fling) dismisses; a short drag springs back. A stationary tap on the backdrop still dismisses.
Loading example…
Props
| Prop | Type | Default | Description |
|---|---|---|---|
onClose required | () => void | — | Called when the overlay requests to close (Escape, overlay click, close button). |
opened required | boolean | false | Controlled opened state. |
animation | false | MotionPresetName | MotionPreset | undefined | a subtle drop-in fade. Reduced motion is
always honoured. Exit animates (the panel and scrim fade out before
unmounting) unless `keepMounted` is set. | Enter/exit animation — a motion preset name, an inline {@link MotionPreset}, or `false` to disable. |
animationConfig | SpringConfig | undefined | — | Spring config for the drag settle (reanimated `withSpring`). |
aria-describedby | string | undefined | — | Additional content description id(s). |
aria-label | string | undefined | "Modal" | Accessible label used when no visible title is provided. |
aria-labelledby | string | undefined | — | Explicit label id used when composing a custom title. |
centered | boolean | undefined | false | Center the content vertically inside the viewport. |
children | ReactNode | Modal body content goes here. | Modal body content. |
closeButtonProps | CloseButtonProps | undefined | — | Props forwarded to the header `CloseButton` — customise its `aria-label`, `icon`, `iconSize`, `size`, `variant`, `radius`, etc. A custom `onPress` overrides the default `onClose` wiring. |
closeOnClickOutside | boolean | undefined | true | Close when the user clicks the overlay scrim. |
closeOnEscape | boolean | undefined | true | Close when the user presses Escape (web). |
disabled system | boolean | undefined | — | |
dragThreshold | number | undefined | 0.3 | Distance dragged, as a fraction of the panel height, past which releasing dismisses (a downward fling always dismisses). |
dragToDismiss | boolean | undefined | false | Allow dragging the panel down to dismiss (reanimated + gesture, the same mechanic as `@knitui/sheet`). The CSS enter/exit motion is unchanged; this only adds the interactive drag-to-close. |
duration | number | undefined | — | Animation speed in ms — overrides the preset's duration while keeping its easing. Ignored when `animation` is `false` or reduced motion is on. |
fullScreen | boolean | undefined | false | Expand the modal to fill the entire screen. |
keepMounted | boolean | undefined | false | Keep mounted while closed. |
lockScroll | boolean | undefined | true | Lock body scroll while opened (web). |
overlayAnimation | false | MotionPresetName | MotionPreset | undefined | "fade". Reduced motion is
always honoured. The content frame's own animation is supplied separately by the
consumer (`Modal`/`Drawer`) on its content frame; pass `false` here to keep the
scrim in lockstep when the consumer disables that. | Enter/exit animation for the overlay scrim — a motion preset name, an inline {@link MotionPreset}, or `false` to disable. |
overlayProps | OverlayProps | undefined | — | Props forwarded to the underlying `Overlay` scrim. |
padding | number | SpaceTokens | Animated.AnimatedNode | "safe" | null | undefined | "$md" | Inner spacing for the header and body. |
radius system | string | number | undefined | "md" | Content corner radius. |
returnFocus | boolean | undefined | true | Return focus to the previously-focused element on close (web). |
shadow system | "xs" | "sm" | "md" | "lg" | "xl" | "xxs" | "xxl" | undefinedxxs · xs · sm · md · lg · xl · xxl | "xl" | Drop-shadow elevation of the content panel (xxs–xxl). |
size system | string | number | undefinedxxs · xs · sm · md · lg · xl · xxl | "md" | Content width — key (xxs–xxl), px number, or CSS string. |
styles system | ModalStyles | undefined | — | Uniform per-slot style passthrough. See {@link ModalStyles}. |
theme system | ThemeName | null | undefined | — | Applies a theme to this element |
title | ReactNode | Modal title | Modal title rendered in the header. |
trapFocus | boolean | undefined | true | Trap keyboard focus while opened (web). |
withCloseButton | boolean | undefined | true | Show the close button in the header. |
withHeaderDivider | boolean | undefined | false | Render a hairline divider under the header. |
withinPortal | boolean | undefined | true | Render inside a `Portal`. |
withOverlay | boolean | undefined | true | Render a dimmed backdrop behind the modal. |
xOffset | number | SpaceTokens | Animated.AnimatedNode | "safe" | null | undefined | "$xl" | Horizontal gap from viewport edges. |
yOffset | number | SpaceTokens | Animated.AnimatedNode | "safe" | null | undefined | "$xl"
(a cross-platform theme token; Mantine defaults to the web-only `5dvh`). | Vertical gap from viewport edges. |
zIndex | number | undefined | 200 | Root `z-index`. |
Style slots
Every part of Modal can be styled through the styles prop. Explicit props on the component always win over slot styles.
| Slot | Usage |
|---|---|
body | styles={{ body: { … } }} |
closeButton | styles={{ closeButton: { … } }} |
content | styles={{ content: { … } }} |
header | styles={{ header: { … } }} |
overlay | styles={{ overlay: { … } }} |
title | styles={{ title: { … } }} |
Accessibility & DOM props (2)
| Prop | Type |
|---|---|
key | Key | null | undefined |
ref | Ref<TamaguiElement> | undefined |
Plus 493 inherited style props from Box — the full Tamagui/React Native style surface, including token shorthands like p, mx, bg and c. See Tokens for the scales they accept, or the full list.