Skip to content

Modal

Modals are overlay containers for focused tasks and important content that requires user attention.

Use Modal for short forms, multi-section content, or custom layouts. For simple yes/no decisions, prefer Dialog or AlertDialog.

import {
Modal,
ModalHeader,
ModalFooter,
Button,
Typography,
} from '@truongdq01/ui';
<Modal open={isOpen} onClose={() => setIsOpen(false)}>
<ModalHeader title="Modal Title" />
<Typography variant="body2" color="secondary">
Modal content
</Typography>
<ModalFooter>
<Button label="Close" onPress={() => setIsOpen(false)} />
</ModalFooter>
</Modal>;

Centered modals apply token-driven layout automatically:

  • Host inset — horizontal and vertical margin from screen edges (modal.hostInset)
  • Safe area — host padding respects notch and home indicator (via safe-area insets)
  • Container — internal padding, rounded corners, maxWidth: 400, soft elevation
  • Keyboard — iOS uses KeyboardAvoidingView padding behavior for form content

fullScreen skips host inset; the consumer controls insets inside the surface.

PropTypeDefaultDescription
openboolean—Required. Modal open state
onClose() => void—Callback when closing
childrenReactNode—Modal content
fullScreenbooleanfalseFull-screen surface (no host inset)
keepMountedbooleanfalseKeep in DOM when closed
hideBackdropbooleanfalseHide backdrop overlay
disableAutoFocusbooleanfalseDisable auto focus
disableEscapeKeyDownbooleanfalseDisable ESC key close
accessibilityLabelstring"Modal"Accessibility label for modal content
backdropAccessibilityLabelstring"Dismiss modal"Accessibility label for the backdrop dismiss button
BackdropComponentComponentType—Custom backdrop component
BackdropPropsobject—Props for backdrop
contentContainerStyleStyleProp<ViewStyle>—Override container surface styles (padding, bg, etc.)
function BasicModal() {
const [open, setOpen] = useState(false);
return (
<>
<Button label="Open Modal" onPress={() => setOpen(true)} />
<Modal open={open} onClose={() => setOpen(false)}>
<ModalHeader title="Modal Title" />
<Typography variant="body2" color="secondary">
Click outside or use the backdrop dismiss action to close.
</Typography>
<ModalFooter>
<Button label="Close" onPress={() => setOpen(false)} />
</ModalFooter>
</Modal>
</>
);
}
function FormModal() {
const [open, setOpen] = useState(false);
const [name, setName] = useState('');
return (
<>
<Button label="Add User" onPress={() => setOpen(true)} />
<Modal open={open} onClose={() => setOpen(false)}>
<ModalHeader title="Add New User" />
<Input label="Name" value={name} onChangeText={setName} />
<ModalFooter>
<Button label="Cancel" variant="outline" onPress={() => setOpen(false)} />
<Button label="Save" onPress={handleSave} />
</ModalFooter>
</Modal>
</>
);
}

Use contentContainerStyle to override the default container tokens (background, padding, radius):

<Modal
open={open}
onClose={() => setOpen(false)}
contentContainerStyle={{ backgroundColor: tokens.color.brand.default }}
>
{/* branded content */}
</Modal>
<Modal open={isOpen} onClose={() => setIsOpen(false)} hideBackdrop>
<Typography>Content without backdrop</Typography>
</Modal>
  • Use for focused tasks requiring attention
  • Compose with ModalHeader, ModalFooter, and typography components
  • Keep content concise and scannable
  • Provide clear close mechanism
  • Don’t use for simple confirmations (use Dialog / AlertDialog)
  • Don’t put too much content (use Drawer for complex flows)
  • Don’t nest modals
  • Don’t wrap content in manual #fff boxes — the container already provides padding and surface
<Modal
open={isOpen}
onClose={() => setIsOpen(false)}
accessibilityLabel="Add user form"
>
{/* content */}
</Modal>
  • iOS: Form content shifts with the keyboard via KeyboardAvoidingView (padding behavior).
  • Android: Hardware back triggers onRequestClose (respects disableEscapeKeyDown).

Native reference: apps/example/app/components/Modal.tsx — basic, form, full-screen, and custom surface demos.

Run cd apps/example && bun run ios and verify inset, safe area, and keyboard behavior. See Example app guide and Visual Baseline → Native QA.

  • Dialog — Pre-styled confirmation/information dialogs
  • AlertDialog — Opinionated alert with built-in actions
  • Drawer — Side panel overlays
  • BottomSheet — Mobile-optimized bottom sheets