Modal Component
Modal Examples with useModal Hook
Simple Modal
Localized labels
None of the three modals below is given an agree, a disagree or a closeTitle prop. Every label — the two buttons and the accessible name of the header close button — is read from the components.modal bundle. Switch the language of the lab and reopen them : the labels follow.
Popover mode — light, non-blocking (usePopover)
Opt-in usePopover: the modal renders through the browser's native Popover API instead of <dialog>. It can be opened declaratively (a button with popovertarget, no JS) or via useModal. Escape and a backdrop click close it. It does not block the page — use it for light panels, not for blocking confirmations.
Popover modal (declarative)
Opened by a button with popovertarget — zero JavaScript. Press ESC or click the backdrop to close.
Popover modal (via useModal)
Same popover mode, opened and closed through the useModal hook.
Responsive Fullscreen (Breakpoint)
Toggle Modal (with State Tracking)
Alert Modals (Single Button)
Confirmation Modals (Two Buttons)
Fullscreen Modal
Responsive & Placement
Custom Width
Behavior Options
Custom Footer
Custom Footer Node — sticky footer + scrollable content
When to use footerNode
Use the footerNode prop when the standardagree / disagree footer is too rigid — typically for forms with a status text, custom buttons, or any layout that does not fit the default modal-action row.
✅ What it gives you
- Footer always pinned at the bottom of the modal-box
- Content area scrolls on its own (smooth, internal)
- Header stays at the top
- No need for
!importantoverrides - No need for
modalBoxClassName="flex flex-col"boilerplate
⚠️ Precedence rules
When footerNode is set, these props are ignored:
agree, disagree, agreeColor, disagreeColor, agreeIcon, disagreeIcon, showAgree, showDisagree, showFooter, footerReverse, footerClassName, footerOptions, onAgree, onCancel
A console.warn is emitted in dev if any of them are passed alongside.
footerNode) is unchanged: the existingshowFooter behaviour with sticky agree/disagree row still works exactly as before.Before / After
❌ Before (manual recipe — 8 lines, 5 ! markers)
<Modal contentClassName ="!overflow-hidden !p-0 flex flex-col flex-1 min-h-0" modalBoxClassName="!overflow-hidden flex flex-col" showFooter={false}> <div className="flex-1 min-h-0 overflow-y-auto ..."> {form fields} </div> <div className="shrink-0 flex border-t bg-base-100 ..."> {status + cancel + save} </div></Modal>✅ After — 1 prop, no overrides
<Modal title="Edit profile" footerNode={<FormFooter ... />}> <form className="flex flex-col gap-4"> {form fields} </form></Modal>// modal-box auto: flex flex-col// content auto: flex-1 min-h-0 overflow-y-autoForm in Modal
useModal Hook Usage
const { modalRef, open, close, toggle, isOpen } = useModal() ;// With callbacksconst { modalRef, open } = useModal({ onOpen: () => console.log('Opened'), onClose: () => console.log('Closed'),}) ;<Button onClick={ open }>Open</Button><Modal ref={ modalRef }>Content</Modal>Stacked Modals (Nesting)
You can open multiple modals on top of each other. The browser handles the stacking order.
Toast over Modal
Click to verify that toasts appear above the modal backdrop. Test case: native <dialog> top layer vs ToastProvider popover.
These buttons fire a toast first, then open a modal a few hundred milliseconds later. Without the MutationObserver in the provider, the modal would steal the top of the top-layer stack and hide the toast. With it, the toast popover is re-promoted as soon as the new <dialog> opens.
Try every combination (3 × 3 = 9 positions): top / middle / bottom × start / center / end. Each toast should anchor at the chosen corner, edge or center — independently of where the modal sits.
CRUD Hooks Demo
useAddModal, useEditModal, useRemoveModal
| Name | Phone | Role | Actions | |
|---|---|---|---|---|
AJ Alice Johnson | alice@example.com | 555-0101 | Developer | |
BS Bob Smith | bob@example.com | 555-0102 | Designer | |
CB Charlie Brown | charlie@example.com | 555-0103 | Manager | |
DP Diana Prince | diana@example.com | 555-0104 | Developer |
useAddModal State
useEditModal State
useRemoveModal State
InputModal - Open on Focus Demo
Click on the input or use the button to open the modal
With openOnFocus
Click the input field or the button to open
#3b82f6
Without openOnFocus
Only the button opens the modal
When to use openOnFocus?
✅ Good for:
- Date pickers
- Time pickers
- Color pickers
- Single-click selections
- Read-only inputs
❌ Avoid for:
- Complex forms
- Multi-step selections
- When typing is needed
- File uploads
- Editable inputs
// ✅ Pattern correct avec état temporaireconst [value, setValue] = useState(initial) ;const [tempValue, setTempValue] = useState(initial) ;<InputModal value={value} // Affiche finale onModalOpen={() => setTempValue(value)} onAgree={() => setValue(tempValue)}> <input value={tempValue} onChange={setTempValue} /></InputModal>Additional Options
Hide Action Button
Use showActionButton={false} to hide the button
Custom onFocus Handler
Combine with your own focus handler