Components
Dialog
A modal shell with focus trapping, deliberate content regions, and a bare host for larger product composites.
Anatomy
Header, Body, and Footer provide the spacing contract. Title labels the dialog automatically. Focus trapping, scroll locking, focus return, and Escape handling come from Base UI.
import { Button, Dialog } from "@karnstack/dowel";
<Dialog.Root>
<Dialog.Trigger render={<Button>Delete workspace</Button>} />
<Dialog.Portal>
<Dialog.Backdrop />
<Dialog.Popup>
<Dialog.Header>
<Dialog.Title>Delete workspace</Dialog.Title>
<Dialog.Description>
This removes every project in it. It cannot be undone.
</Dialog.Description>
</Dialog.Header>
<Dialog.Footer>
<Dialog.Close render={<Button>Cancel</Button>} />
<Dialog.Close render={<Button variant="danger">Delete</Button>} />
</Dialog.Footer>
</Dialog.Popup>
</Dialog.Portal>
</Dialog.Root>Dialog.Portal renders a plain div. Never put an inline transform or filter on it. Either one creates a containing block and breaks the popup's fixed positioning.
With a form
Put controls in Body and actions in Footer. The regions keep spacing and dividers consistent across every small modal.
<Dialog.Popup>
<Dialog.Header>
<Dialog.Title>New project</Dialog.Title>
</Dialog.Header>
<Dialog.Body>
<Field.Root>
<Field.Label>Name</Field.Label>
<Input placeholder="dowel" />
</Field.Root>
</Dialog.Body>
<Dialog.Footer>
<Dialog.Close render={<Button>Cancel</Button>} />
<Button variant="primary">Create</Button>
</Dialog.Footer>
</Dialog.Popup>With a composer
Use the bare popup when a product composite already owns its surface. Dialog still owns modal behavior and Composer owns the creation experience.
<Dialog.Root>
<Dialog.Trigger render={<Button>New work item</Button>} />
<Dialog.Portal>
<Dialog.Backdrop />
<Dialog.Popup variant="bare" aria-label="Create work item">
<Composer.Root onSubmit={createItem}>
<Composer.Body>
<Composer.Title name="title" placeholder="Add title" />
<Composer.Description
name="description"
placeholder="Add a description"
/>
</Composer.Body>
<Composer.Properties>
<PropertyPill label="Triage" />
<PropertyPill label="Assignee" />
</Composer.Properties>
<Composer.Footer>
<Composer.Actions>
<Button variant="primary" type="submit">Create item</Button>
</Composer.Actions>
</Composer.Footer>
</Composer.Root>
</Dialog.Popup>
</Dialog.Portal>
</Dialog.Root>