Accessible modal dialog rendered into document.body via a portal. Uses useFocusTrap and useScrollLock internally.
Import
import { Modal } from '@kivora/react';
Usage
import { Modal, Button, useDisclosure } from '@kivora/react';
function Example() {
const { isOpen, open, close } = useDisclosure();
return (
<>
<Button label="Open Modal" onClick={open} />
<Modal isOpen={isOpen} onClose={close} title="Confirm Action">
<p>Are you sure you want to continue?</p>
<div className="flex gap-2 mt-4">
<Button label="Cancel" variant="ghost" onClick={close} />
<Button label="Confirm" onClick={close} />
</div>
</Modal>
</>
);
}
Sizes
Control modal width with the size prop:
<Modal isOpen={isOpen} onClose={close} size="sm" title="Small">
<p>Compact modal content</p>
</Modal>
<Modal isOpen={isOpen} onClose={close} size="lg" title="Large">
<p>Wider modal with more content</p>
</Modal>
<Modal isOpen={isOpen} onClose={close} size="full" title="Full Width">
<p>Uses full viewport width with margin</p>
</Modal>
Available sizes: sm, md (default), lg, xl, full
No Padding
Remove default body padding for custom layouts:
<Modal isOpen={isOpen} onClose={close} noPadding>
<img src="/banner.jpg" alt="Banner" className="w-full" />
<div className="p-6">
<p>Custom padded content</p>
</div>
</Modal>
Without Title
Omit the title prop to render without a header:
<Modal isOpen={isOpen} onClose={close}>
<div className="text-center p-4">
<h3 className="text-xl font-bold mb-2">Custom Header</h3>
<p>Full control over the content</p>
</div>
</Modal>
Disable Backdrop Close
Prevent closing when clicking outside:
<Modal
isOpen={isOpen}
onClose={close}
title="Required Action"
closeOnBackdrop={false}
>
<p>You must complete this action</p>
<Button label="Complete" onClick={close} />
</Modal>
Disable Escape Key
Prevent closing with the Escape key:
<Modal
isOpen={isOpen}
onClose={close}
title="Critical Dialog"
closeOnEscape={false}
>
<p>This dialog requires explicit confirmation</p>
</Modal>
Props
Whether the modal is visible
Callback to close the modal
Optional title rendered in the modal header with close button
size
'sm' | 'md' | 'lg' | 'xl' | 'full'
default:"md"
Maximum width preset
Close when clicking the backdrop
Close when pressing Escape key
Remove default body padding
Additional CSS classes for the modal panel
Accessibility
- Uses
role="dialog" and aria-modal="true"
- Automatically manages focus trap within the modal
- Locks body scroll when open
- Links title with
aria-labelledby
- Close button has
aria-label
- Escape key support (configurable)
Features
- Portal rendering into
document.body
- Smooth fade and scale animations
- Focus trap using
useFocusTrap hook
- Scroll lock using
useScrollLock hook
- Backdrop blur effect
- Configurable sizes
- Optional header with close button
- Flexible padding control