Dialog

Modal panel for forms, details, and confirmations.

Open a focused panel over the page for forms, details, or confirmations. Dismiss it with Escape or the close control.

tsx
import { Button } from "@/components/ui/button"import {  Dialog,  DialogClose,  DialogContent,  DialogDescription,  DialogFooter,  DialogHeader,  DialogTitle,  DialogTrigger,} from "@/components/ui/dialog"import { Field, FieldGroup } from "@/components/ui/field"import { Input } from "@/components/ui/input"import { Label } from "@/components/ui/label"export function Example() {  return (    <Dialog>      <form>        <DialogTrigger render={<Button variant="outline" />}>          Open Dialog        </DialogTrigger>        <DialogContent className="sm:max-w-sm">          <DialogHeader>            <DialogTitle>Edit profile</DialogTitle>            <DialogDescription>              Make changes to your profile here. Click save when you&apos;re              done.            </DialogDescription>          </DialogHeader>          <FieldGroup>            <Field>              <Label htmlFor="name-1">Name</Label>              <Input id="name-1" name="name" defaultValue="Pedro Duarte" />            </Field>            <Field>              <Label htmlFor="username-1">Username</Label>              <Input                id="username-1"                name="username"                defaultValue="@peduarte"              />            </Field>          </FieldGroup>          <DialogFooter>            <DialogClose render={<Button variant="outline" />}>              Cancel            </DialogClose>            <Button type="submit">Save changes</Button>          </DialogFooter>        </DialogContent>      </form>    </Dialog>  )}

Installation

npx @arctis-sh/@arctis-sh/ui@latest add dialog

Usage

import { Button } from "@/components/ui/button"import {  Dialog,  DialogClose,  DialogContent,  DialogDescription,  DialogFooter,  DialogHeader,  DialogTitle,  DialogTrigger,} from "@/components/ui/dialog"
<Dialog>  <DialogTrigger render={<Button variant="outline" />}>    Edit profile  </DialogTrigger>  <DialogContent>    <DialogHeader>      <DialogTitle>Edit profile</DialogTitle>      <DialogDescription>        Update your name and email for this workspace.      </DialogDescription>    </DialogHeader>  </DialogContent></Dialog>

Composition

Dialog
├── DialogTrigger
└── DialogContent
    ├── DialogHeader
    │   ├── DialogTitle
    │   └── DialogDescription
    └── DialogFooter

Custom close button

Replace the default close control with a button in the footer.

tsx
import { Button } from "@/components/ui/button"import {  Dialog,  DialogClose,  DialogContent,  DialogDescription,  DialogFooter,  DialogHeader,  DialogTitle,  DialogTrigger,} from "@/components/ui/dialog"import { Input } from "@/components/ui/input"import { Label } from "@/components/ui/label"export function Example() {  return (    <Dialog>      <DialogTrigger render={<Button variant="outline" />}>        Share      </DialogTrigger>      <DialogContent className="sm:max-w-md">        <DialogHeader>          <DialogTitle>Share link</DialogTitle>          <DialogDescription>            Anyone who has this link will be able to view this.          </DialogDescription>        </DialogHeader>        <div className="flex items-center gap-2">          <div className="grid flex-1 gap-2">            <Label htmlFor="link" className="sr-only">              Link            </Label>            <Input              id="link"              defaultValue="https://example.com/share/a1b2c3d4"              readOnly            />          </div>        </div>        <DialogFooter className="sm:justify-start">          <DialogClose render={<Button />}>Close</DialogClose>        </DialogFooter>      </DialogContent>    </Dialog>  )}

No close button

Set showCloseButton={false} on DialogContent to hide the default close button.

tsx
import { Button } from "@/components/ui/button"import {  Dialog,  DialogContent,  DialogDescription,  DialogHeader,  DialogTitle,  DialogTrigger,} from "@/components/ui/dialog"export function Example() {  return (    <Dialog>      <DialogTrigger render={<Button variant="outline" />}>        No Close Button      </DialogTrigger>      <DialogContent showCloseButton={false}>        <DialogHeader>          <DialogTitle>No Close Button</DialogTitle>          <DialogDescription>            This dialog doesn&apos;t have a close button in the top-right            corner.          </DialogDescription>        </DialogHeader>      </DialogContent>    </Dialog>  )}

Keep actions in view while longer content scrolls.

tsx
import { Button } from "@/components/ui/button"import {  Dialog,  DialogClose,  DialogContent,  DialogDescription,  DialogFooter,  DialogHeader,  DialogTitle,  DialogTrigger,} from "@/components/ui/dialog"export function Example() {  return (    <Dialog>      <DialogTrigger render={<Button variant="outline" />}>        Sticky Footer      </DialogTrigger>      <DialogContent>        <DialogHeader>          <DialogTitle>Sticky Footer</DialogTitle>          <DialogDescription>            This dialog has a sticky footer that stays visible while the content            scrolls.          </DialogDescription>        </DialogHeader>        <div className="-mx-4 max-h-[50vh] overflow-y-auto px-4">          {Array.from({ length: 10 }).map((_, index) => (            <p key={index} className="mb-4 leading-normal tracking-wide">              Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do              eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut              enim ad minim veniam, quis nostrud exercitation ullamco laboris              nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in              reprehenderit in voluptate velit esse cillum dolore eu fugiat              nulla pariatur. Excepteur sint occaecat cupidatat non proident,              sunt in culpa qui officia deserunt mollit anim id est laborum.            </p>          ))}        </div>        <DialogFooter>          <DialogClose render={<Button variant="outline" />}>            Close          </DialogClose>        </DialogFooter>      </DialogContent>    </Dialog>  )}

Scrollable content

Let longer content scroll while the header stays in view.

tsx
import { Button } from "@/components/ui/button"import {  Dialog,  DialogContent,  DialogDescription,  DialogHeader,  DialogTitle,  DialogTrigger,} from "@/components/ui/dialog"export function Example() {  return (    <Dialog>      <DialogTrigger render={<Button variant="outline" />}>        Scrollable Content      </DialogTrigger>      <DialogContent>        <DialogHeader>          <DialogTitle>Scrollable Content</DialogTitle>          <DialogDescription>            This is a dialog with scrollable content.          </DialogDescription>        </DialogHeader>        <div className="-mx-4 max-h-[50vh] overflow-y-auto px-4">          {Array.from({ length: 10 }).map((_, index) => (            <p key={index} className="mb-4 leading-normal tracking-wide">              Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do              eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut              enim ad minim veniam, quis nostrud exercitation ullamco laboris              nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in              reprehenderit in voluptate velit esse cillum dolore eu fugiat              nulla pariatur. Excepteur sint occaecat cupidatat non proident,              sunt in culpa qui officia deserunt mollit anim id est laborum.            </p>          ))}        </div>      </DialogContent>    </Dialog>  )}

API Reference

Dialog

PropTypeDefault
openboolean
defaultOpenbooleanfalse
onOpenChange(open: boolean) => void
onOpenChangeComplete(open: boolean) => void
modalboolean | "trap-focus"true
disablePointerDismissalbooleanfalse
<Dialog>  <DialogTrigger render={<Button variant="outline" />}>    Open  </DialogTrigger>  <DialogContent>...</DialogContent></Dialog>

DialogTrigger

Renders a native button by default. Pass a Button with the Base UI render prop.

PropTypeDefault
classNamestring
renderReact.ReactElement
<DialogTrigger render={<Button variant="outline" />}>  Open</DialogTrigger>

DialogClose

Closes the dialog. Prefer render={<Button … />} so actions match your buttons.

PropTypeDefault
classNamestring
renderReact.ReactElement
<DialogClose render={<Button variant="outline" />}>  Cancel</DialogClose>

DialogContent

Centered panel with an overlay and the shared Arctis open animation. A top-right close control is included by default.

PropTypeDefault
classNamestring
showCloseButtonbooleantrue
<DialogContent className="sm:max-w-md" showCloseButton>  ...</DialogContent>

DialogHeader

PropTypeDefault
classNamestring
<DialogHeader>  <DialogTitle>Title</DialogTitle>  <DialogDescription>Description</DialogDescription></DialogHeader>

DialogFooter

PropTypeDefault
classNamestring
showCloseButtonbooleanfalse
<DialogFooter>  <DialogClose render={<Button variant="outline" />}>    Cancel  </DialogClose>  <Button>Save</Button></DialogFooter>

DialogTitle

PropTypeDefault
classNamestring
<DialogTitle>Title</DialogTitle>

DialogDescription

PropTypeDefault
classNamestring
<DialogDescription>Description</DialogDescription>

DialogPortal

PropTypeDefault
containerHTMLElementdocument.body

DialogOverlay

Scrim behind the panel. Rendered automatically by DialogContent.

PropTypeDefault
classNamestring