labsUI

Dialog

Portal modal with blurred backdrop, spring scale-in, focus trap, Esc and scroll lock.

npx @kznlabs/labsui add dialog
import {  Dialog,  DialogClose,  DialogContent,  DialogDescription,  DialogFooter,  DialogHeader,  DialogTitle,  DialogTrigger,} from "@/components/ui/dialog";export function EditProfile() {  return (    <Dialog>      <DialogTrigger variant="outline">Edit profile</DialogTrigger>      <DialogContent>        <DialogHeader>          <DialogTitle>Edit profile</DialogTitle>          <DialogDescription>Changes apply to your account.</DialogDescription>        </DialogHeader>        <DialogFooter>          <DialogClose>Cancel</DialogClose>        </DialogFooter>      </DialogContent>    </Dialog>  );}

<Dialog>

State root. Controlled (open + onOpenChange) or uncontrolled.

  • children*
    ReactNode

    DialogTrigger and DialogContent.

  • defaultOpendefault false
    boolean

    Open at first render (uncontrolled).

  • onOpenChange
    (open: boolean) => void

    Called on the trigger, Esc, backdrop click or DialogClose.

  • open
    boolean

    Controlled state; pair with onOpenChange.

PropTypeDefault
children*

DialogTrigger and DialogContent.

ReactNode—
defaultOpen

Open at first render (uncontrolled).

booleanfalse
onOpenChange

Called on the trigger, Esc, backdrop click or DialogClose.

(open: boolean) => void—
open

Controlled state; pair with onOpenChange.

boolean—

<DialogTrigger>

  • children
    ReactNode

    Label; its width is reserved so loading and success never resize the button.

  • confirmLabel
    ReactNode

    Two-step action: first click swaps the label to this, second click runs onClick.

  • confirmTimeout
    number

    Ms before an armed confirm step resets. Also resets on blur or Esc.

  • loading
    boolean

    Disables the button and shows a spinner before the label.

  • loadingLabel
    ReactNode

    Label shown while loading, with the spinner. Defaults to children.

  • size
    "default" | "sm" | "lg" | "icon"

    Height and padding; "icon" is square, so give it an aria-label.

  • status
    ButtonStatus

    In-place feedback: loading spins, success swaps the label to successLabel.

  • successLabel
    ReactNode

    Text shown on status="success", with a check icon. Defaults to "Done".

  • swap
    SwapDirection

    Where the old label slides out to on a swap. Default "left".

  • variant
    "default" | "secondary" | "outline" | "ghost" | "destructive"

    Fill and emphasis: one primary action per view, destructive for irreversible ones.

PropTypeDefault
children

Label; its width is reserved so loading and success never resize the button.

ReactNode—
confirmLabel

Two-step action: first click swaps the label to this, second click runs onClick.

ReactNode—
confirmTimeout

Ms before an armed confirm step resets. Also resets on blur or Esc.

number—
loading

Disables the button and shows a spinner before the label.

boolean—
loadingLabel

Label shown while loading, with the spinner. Defaults to children.

ReactNode—
size

Height and padding; "icon" is square, so give it an aria-label.

"default" | "sm" | "lg" | "icon"—
status

In-place feedback: loading spins, success swaps the label to successLabel.

ButtonStatus—
successLabel

Text shown on status="success", with a check icon. Defaults to "Done".

ReactNode—
swap

Where the old label slides out to on a swap. Default "left".

SwapDirection—
variant

Fill and emphasis: one primary action per view, destructive for irreversible ones.

"default" | "secondary" | "outline" | "ghost" | "destructive"—

Also accepts every Button prop.

<DialogClose>

  • children
    ReactNode

    Label; its width is reserved so loading and success never resize the button.

  • confirmLabel
    ReactNode

    Two-step action: first click swaps the label to this, second click runs onClick.

  • confirmTimeout
    number

    Ms before an armed confirm step resets. Also resets on blur or Esc.

  • loading
    boolean

    Disables the button and shows a spinner before the label.

  • loadingLabel
    ReactNode

    Label shown while loading, with the spinner. Defaults to children.

  • size
    "default" | "sm" | "lg" | "icon"

    Height and padding; "icon" is square, so give it an aria-label.

  • status
    ButtonStatus

    In-place feedback: loading spins, success swaps the label to successLabel.

  • successLabel
    ReactNode

    Text shown on status="success", with a check icon. Defaults to "Done".

  • swap
    SwapDirection

    Where the old label slides out to on a swap. Default "left".

  • variantdefault "outline"
    "default" | "secondary" | "outline" | "ghost" | "destructive"

    Fill and emphasis: one primary action per view, destructive for irreversible ones.

PropTypeDefault
children

Label; its width is reserved so loading and success never resize the button.

ReactNode—
confirmLabel

Two-step action: first click swaps the label to this, second click runs onClick.

ReactNode—
confirmTimeout

Ms before an armed confirm step resets. Also resets on blur or Esc.

number—
loading

Disables the button and shows a spinner before the label.

boolean—
loadingLabel

Label shown while loading, with the spinner. Defaults to children.

ReactNode—
size

Height and padding; "icon" is square, so give it an aria-label.

"default" | "sm" | "lg" | "icon"—
status

In-place feedback: loading spins, success swaps the label to successLabel.

ButtonStatus—
successLabel

Text shown on status="success", with a check icon. Defaults to "Done".

ReactNode—
swap

Where the old label slides out to on a swap. Default "left".

SwapDirection—
variant

Fill and emphasis: one primary action per view, destructive for irreversible ones.

"default" | "secondary" | "outline" | "ghost" | "destructive""outline"

Also accepts every Button prop.

<DialogContent>

Portal + blurred backdrop + spring scale-in. Esc/backdrop close, focus trap, scroll lock.

  • children*
    ReactNode

    Header, body and footer.

  • alertdefault false
    boolean

    Confirm-a-destructive-action mode: role="alertdialog", backdrop click does not close.

  • showClosedefault !alert
    boolean

    Close button in the corner. Off by default for alert dialogs.

PropTypeDefault
children*

Header, body and footer.

ReactNode—
alert

Confirm-a-destructive-action mode: role="alertdialog", backdrop click does not close.

booleanfalse
showClose

Close button in the corner. Off by default for alert dialogs.

boolean!alert

<DialogHeader>

Also accepts every <div> prop (none of its own).

<DialogFooter>

Also accepts every <div> prop (none of its own).

<DialogTitle>

Also accepts every <h2> prop (none of its own).

<DialogDescription>

Also accepts every <p> prop (none of its own).

useDialog()

useDialog() => Ctx

useModal()

Modal behavior shared by Dialog and Drawer: focus first field, trap Tab, restore focus, lock page scroll, close on Esc (topmost modal only). Attach the returned ref to the panel.

useModal() => RefObject<HTMLDivElement | null>
type Ctx
{ open: boolean; setOpen: (open: boolean) => void; titleId: string; descId: string }

* required. Every component also takes className.