Count: 0
Some page content
You can interact with the content below the non-modal dialog.Try click the 2 buttons above.
Display overlay area on top of a page, represents a modal or non-modal dialog box.
Build on top of the native HTML <dialog/>
element.
import {Dialog} from '@kaiverse/k/ui'
Some examples of how to use the Dialog component.
function BasicDialog() { const [openDialog, setOpenDialog] = useState(false) return ( <> <button type="button" onClick={() => setOpenDialog(true)}> Open Dialog </button> <Dialog open={openDialog} onClose={() => setOpenDialog(false)}> <Dialog.Header> <Dialog.Title>Dialog header</Dialog.Title> <Dialog.CloseButton /> </Dialog.Header> <Dialog.Content>Dialog content</Dialog.Content> <Dialog.Footer> <button type="button" onClick={() => setOpenDialog(false)}> Close </button> Dialog Footer </Dialog.Footer> </Dialog> </> )}
When submitting a <form>
that is nested within a <Dialog>
,
you can close that <Dialog>
by using form method method="dialog"
or set formmethod="dialog"
to the <button>
used to submit the form.
Also as a result, the onClose
event will be fired.
Let use the drawer
variant for this example.
{ "keyword": "" }
import {Dialog} from '@kaiverse/k/ui'import {useState, type FormEventHandler} from 'react'import {useDisclosure} from '@kaiverse/k/hooks'import JunkArticle from './junk-articles'
export default function DialogControlledByForm() { const [opened, {open, close}] = useDisclosure(false) const [keyword, setKeyword] = useState('') // just for display form value
const handleFormSubmit: FormEventHandler<HTMLFormElement> = (e) => { const formData = new FormData(e.currentTarget) setKeyword((formData.get('keyword') as string) || '')
if (!formData.get('keepFormValue')) { e.currentTarget.reset() } }
return ( <> <button className="btn btn-neutral" type="button" onClick={open}> Open Drawer </button> <section className="my-4"> <strong>Submitted form values:</strong> <pre className="p-2 w-full rounded-lg bg-base-100 whitespace-pre-wrap [overflow-wrap:anywhere]"> {JSON.stringify({keyword}, null, 2)} </pre> </section>
<Dialog open={opened} variant="drawer" offset="1.5rem" onClose={close}> <Dialog.Header> <Dialog.Title>Drawer controlled by form</Dialog.Title> <Dialog.CloseButton /> </Dialog.Header> <Dialog.Content className="py-0"> <form className="space-y-4 border-2 border-neutral-200 rounded-lg p-4" id="form-manipulate-drawer" method="dialog" onSubmit={handleFormSubmit} > <h3 className="sticky sticky-bg inset-x-0 top-0">Drawer Form</h3> <p> In this form example, all inputs are uncontrolled input. <br /> Check the "Keep form value" checkbox to persist the form value after submitting and closing the Dialog. </p> <label className="form-control w-full max-w-xs"> <span className="label label-text">Keyword</span> <input className="input input-bordered w-full max-w-xs" name="keyword" type="text" placeholder="Type some keyword" autoFocus /> </label> <label className="items-center flex gap-2 cursor-pointer"> <span className="label-text">Keep form value:</span> <input className="checkbox" name="keepFormValue" type="checkbox" /> </label> </form> <JunkArticle /> {/* Just to make the drawer's content long */} </Dialog.Content>
<Dialog.Footer> <button className="btn btn-neutral btn-outline" form="form-manipulate-drawer" type="reset" onClick={close} // remove this line if you only want to reset the form value > Cancel </button> <button className="btn btn-secondary" form="form-manipulate-drawer" type="submit"> Submit </button> </Dialog.Footer> </Dialog> </> )}
Dialog.Header
— a fully customizable header, usually contains a title and the close button.Dialog.Title
— render a h2
element.Dialog.CloseButton
— a button that closes the Dialog
, this component must be used inside the Dialog
.Dialog.Content
— a wrapper for the main content of the Dialog
.Dialog.Footer
— bottom section, usually contains actions.For instance, here is a drawer with similar UI as the previous “Controlled by form” example that doesn’t use any compound components.
import {useDisclosure} from '@kaiverse/k/hooks'import {Dialog} from '@kaiverse/k/ui'import JunkArticle from './junk-articles'import {IconX} from '../icon'
export default function WithoutCompoundComponents() { const [opened, {open, close}] = useDisclosure(false)
return ( <> <button className="btn btn-neutral" type="button" onClick={open}> Open Drawer </button> <Dialog className="[&[open]]:flex flex-col" open={opened} variant="drawer" offset="1.5rem" onClose={close} > <header className="p-4 flex items-center justify-between gap-4"> <h2>Drawer controlled by form</h2> <button className="btn btn-ghost btn-circle btn-sm" type="button" onClick={close}> <IconX /> </button> </header> <article className="flex-1 px-4 overflow-y-auto"> <form className="space-y-4 border-2 border-neutral-200 rounded-lg p-4" id="form-dialog-without-compound" method="dialog" > <h3 className="sticky inset-x-0 top-0 sticky-bg">Drawer Form</h3> <p>In this form example, all inputs are uncontrolled input.</p> <label className="form-control w-full max-w-xs"> <span className="label label-text">Keyword</span> <input className="input input-bordered w-full max-w-xs" name="keyword-input" type="text" placeholder="Type something..." autoFocus /> </label> </form> <JunkArticle /> {/* Just to make the drawer's content long */} </article> <footer className="p-4 flex justify-between items-center"> <button className="btn btn-neutral btn-outline" form="form-dialog-without-compound" type="reset" onClick={close} // remove this line if you only want to reset the form value > Cancel </button> <button className="btn btn-secondary" form="form-dialog-without-compound" type="submit"> Submit </button> </footer> </Dialog> </> )}
'use client';
import {Dialog} from '@kaiverse/k/ui'
export default function ClientComponent() { return ( <Dialog open> <Dialog.Header> <Dialog.Title>Dialog header</Dialog.Title> <Dialog.CloseButton /> </Dialog.Header> <Dialog.Content>Dialog content</Dialog.Content> <Dialog.Footer>Dialog Footer</Dialog.Footer> </Dialog> )}
import {Dialog, DialogHeader, DialogTitle, DialogCloseButton, DialogContent, DialogFooter} from '@kaiverse/k/ui'
export default function ServerComponent() { return ( <Dialog open> <DialogHeader> <DialogTitle>Dialog header</DialogTitle> <DialogCloseButton /> </DialogHeader> <DialogContent>Dialog content</DialogContent> <DialogFooter>Dialog Footer</DialogFooter> </Dialog> )}
drawer
A Dialog that slides in from the side of the screen.
Position of the drawer. It only available when variant is set to 'drawer'
.
<Dialog variant="drawer" position="..." />
mobile
WIP A variant that utilizes modern web technologies to replicate the iOS drawer (sheets) experience on the web.
Coming soon…
non-modal
modeA Dialog that has no backdrop and also doesn’t render on the top-layer. It can NOT be closed by pressing the ESC
key and the below page content can be interacted.
Count: 0
<Dialog dialogMode="non-modal" />
Dialog
component build on top of the HTML <dialog/>
element.
By default, it respects the default accessibility behavior and settings of a <dialog/>
element.
You can opt-out some behaviors by using the preventFocus
and preventClose
props.
Key | Description |
---|---|
Escape | Close the Dialog . This behavior will be disabled if dialogMode is 'non-modal' . |
Spacebar | Trigger focusing element. eg: The close button when a Dialog just opened, and the button that opens the Dialog after closing it. You can continue press Spacebar to open/close a Dialog. |
Tab | Shift + Tab | Cycles through all the focusable elements of the Dialog only. |
Variable | Default | Description |
---|---|---|
--k-dialog-animation-timing-fn | cubic-bezier(0.32, 0.72, 0, 1) | Dialog opening and closing stages animation timing function. |
--k-dialog-open-animation-duration | 500ms | Dialog opening animation duration. |
--k-dialog-close-animation-duration | 200ms | Dialog closing animation duration. |
--k-dialog-transition-timing-fn | cubic-bezier(0.32, 0.72, 0, 1) | Dialog opening and closing stages transition timing function. |
--k-dialog-open-transition-duration | 200ms | Opening transition duration of the Dialog and its backdrop. It affects opacity , and discrete transitions (display , overlay ). |
--k-dialog-close-transition-duration | 200ms | Same as --k-dialog-open-transition-duration but for the closing stage. |
--k-dialog-offset | 0 | Dialog’s offset from the edge of current viewport. |
--k-dialog-backdrop-bg | rgba(0, 0, 0, 0.4) | Backdrop background. |
--k-dialog-backdrop-blur | 0 | Backdrop blur effect. It will be used by backdrop-filter ’s blur function. |
--k-dialog-backdrop-opacity | 1 | Backdrop opacity. |
You can set the offset
prop to adjust the Dialog’s position from the edge of the viewport.
<Dialog offset={16} />
We can customize the Dialog’s backdrop by
backdropProps
prop.::backdrop
pseudo-element.<Dialog className="bg-base-100/90" backdropProps={{ blur: 1, opacity: 0.5, background: 'linear-gradient(-25deg,rgba(238,174,202,0.6) 0%,rgba(148,187,233,0.6) 100%)', }}> <Dialog.Header className="italic"> <Dialog.Title>Drawer header</Dialog.Title> </Dialog.Header> <Dialog.Content className="[&_code]:text-info"> We can use <code>backdropProps</code> to style the Dialog's backdrop. </Dialog.Content> <footer className="bg-[radial-gradient(circle,rgba(34,193,195,0.4)_0%,rgba(253,187,45,0.2)_100%)]"> <button type="button"> Close </button> </footer></Dialog>
Name | Type | Description |
---|---|---|
BackdropProps | {background?: string; blur?: string | number; opacity?: number} | backdropProps prop’s options. |
DialogStylingSelectors | 'header' | 'content' | 'footer' | Available selectors of special styles APIs: classNames , styles . |
<Dialog>
PropsName | Type | Default | Description |
---|---|---|---|
variant | 'default' | 'drawer' | 'default' | |
dialogMode | 'modal' | 'non-modal' | 'modal' | 'modal' (1)'non-modal' (2) |
preventFocus | boolean | false | If true , disable a default behavior of <dialog> element: Browser won’t autofocus on the first nested focusable element anymore. |
preventClose | boolean | false | If true , the Dialog won’t close when users press Escape key or click/tap on the backdrop. |
backdropProps | BackdropProps | background: rgba(0,0,0,0.4) blur: 0 opacity: 1 | Styling Dialog’s backdrop. |
offset | number | string | 0 (px) | Dialog’s offset from the edge of current viewport. |
classNames | Partial<Record<DialogStylingSelectors, string>> | — | Applies className to related selector element. |
styles | Partial<Record<DialogStylingSelectors, CSSProperties>> | — | styles[selector] applies inline styles to related selector element ONLY if its style property has not been provided. |
'drawer'
Name | Type | Default | Description |
---|---|---|---|
position | 'right' | 'bottom' | 'left' | 'top' | 'right' | Side of the screen where the 'drawer' variant will be opened. |