Dialog
A window over the page for one focused task, like editing a profile or inviting people. Focus moves in when it opens, stays inside, and goes back when it closes.
Installation
Set up Camaleo once (Installation), then import what you need. It renders on the client.
import { Dialog, DialogTrigger, DialogContent, DialogTitle, DialogDescription, DialogClose, DialogActions } from "@camaleo/react";Anatomy
A dialog-trigger button opens a dialog-backdrop and this popup. Both render in a portal that keeps the skin, mode and brand of the page around the trigger.
Examples
Every example is a real file you can copy. Open them: the dialog wears the skin, mode and brand from the bar above.
Project: Atlas
A form that closes on submit
Click it. Focus starts in the field; submitting saves, closes the dialog, returns focus to the trigger and a status message says what changed.
Opened by something else
When the state lives elsewhere (a menu item, a shortcut), pass open and onOpenChange. Focus still goes back to whatever opened it.
Long content
Scroll only the body, so the title and the buttons stay in view. Wrap it in a ScrollArea: its viewport takes focus, so the keyboard can scroll it.
Doesn't close on outside click
When people type a lot, a stray click shouldn't throw it away. disablePointerDismissal keeps Esc and the buttons working.
A close button in the corner
Every dialog needs a visible way out: touch screen readers have no Esc. Put the icon button last in the code so focus starts on the content.
Wider for a table
There is one default width. Set inline-size on DialogContent when a table needs room; on a phone it still fits the screen.
In context
Dialogs hold a task that belongs to something on the page. These are whole pieces of UI you can copy, in the skin you picked.
Marina Costa
marina@ateliernorte.com
Product designer in Porto Alegre. Into type, maps and coffee.
Team
4 members · 8 seats
- Marina CostaOwner
- Bruno Takahashi
- Carla Mendes
- Diego Alves
October report
Revenue, churn and signups from October 1 to 31, 2026.
Guidelines
People finish it and get back to what they were doing.
It scrolls, hides the page it belongs to and can't be linked. Use a page.
"Invite teammates" and "Send invites" say what happens, also to a screen reader that reads only the title.
The title is the dialog's accessible name. A generic one tells nobody where they are.
Props
onOpenChange to control the state.true traps focus, locks scrolling and blocks outside clicks. trap-focus only traps focus. false leaves the page free.eventDetails.reason says why, for example escape-key or outside-press.DialogTrigger, DialogTitle, DialogDescription and DialogClose take the props of their element, plus render.
DialogContent decides where focus goes:
Styling hooks
Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the popup itself.
Attributes
Tokens it reads
Color
Shape & size
Type & motion
This component only
/* a dialog that fills the screen on phones */
@media (max-width: 40rem) {
.checkout [data-slot="dialog-popup"] {
inline-size: 100vw;
max-block-size: 100dvh;
border-radius: 0;
}
}Accessibility
- The popup has role="dialog". DialogTitle names it and DialogDescription describes it, through aria-labelledby and aria-describedby: always include a title.
- While it is open, the rest of the page is hidden from screen readers (aria-hidden), focus can't leave and the page doesn't scroll.
- A click outside closes it, unless you pass disablePointerDismissal. Esc and the close buttons always work.
- When the element that opened it is gone after closing, point finalFocus at something sensible, and announce the result with role="status".