Dialog
Composable dialog parts for focused tasks and custom layouts.
On this page
Code
import { Dialog } from "@bosunkit/components/dialog";
import { Button } from "@bosunkit/components/button";
import { Field } from "@bosunkit/components/field";
import { Stack } from "@bosunkit/components/stack";
import type { ReactElement } from "react";
export const description: string =
"A composed dialog names its task, moves focus inside, closes with Escape and restores focus to its trigger.";
export default function Showcase(): ReactElement {
return (
<Dialog.Root>
<Dialog.Trigger render={<Button>Name report</Button>} />
<Dialog.Portal>
<Dialog.Backdrop />
<Dialog.Popup>
<Stack space="lg">
<Stack space="xs">
<Dialog.Title>Name report</Dialog.Title>
<Dialog.Description>This title appears in the report library.</Dialog.Description>
</Stack>
<Field.Root>
<Field.Label>Report title</Field.Label>
<Field.Control defaultValue="Daily engineering update" />
</Field.Root>
<div>
<Dialog.Close render={<Button>Done</Button>} />
</div>
</Stack>
</Dialog.Popup>
</Dialog.Portal>
</Dialog.Root>
);
}
01Names describe behaviorUse the primitive for custom composition and a named recipe for an assembled control.
02One state contractControlled values, defaults and change callbacks follow Base UI; event details keep their reason and cancellation.
03Composition keeps semanticsA render target forwards its ref and every received DOM prop so keyboard interaction and accessible names survive.
Composition
Import { Dialog } from @bosunkit/components/dialog. Named parts follow
Base UI Dialog.
Each part retains the upstream render, ref, DOM props, state attributes and event contracts.
The kit supplies its typography, surfaces and scoped overlay presentation.
Examples
Custom composition
Code
import { Dialog } from "@bosunkit/components/dialog";
import { Button } from "@bosunkit/components/button";
import { Field } from "@bosunkit/components/field";
import { Stack } from "@bosunkit/components/stack";
import type { ReactElement } from "react";
export const description: string =
"A composed dialog names its task, moves focus inside, closes with Escape and restores focus to its trigger.";
export default function Showcase(): ReactElement {
return (
<Dialog.Root>
<Dialog.Trigger render={<Button>Name report</Button>} />
<Dialog.Portal>
<Dialog.Backdrop />
<Dialog.Popup>
<Stack space="lg">
<Stack space="xs">
<Dialog.Title>Name report</Dialog.Title>
<Dialog.Description>This title appears in the report library.</Dialog.Description>
</Stack>
<Field.Root>
<Field.Label>Report title</Field.Label>
<Field.Control defaultValue="Daily engineering update" />
</Field.Root>
<div>
<Dialog.Close render={<Button>Done</Button>} />
</div>
</Stack>
</Dialog.Popup>
</Dialog.Portal>
</Dialog.Root>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| motion | boolean | undefined | – | Enable token-based transitions; false disables motion. |
| initialFocus | boolean | React.RefObject<HTMLElement | null> | ((openType: InteractionType) => boolean | HTMLElement | null | void) | undefined | – | Determines the element to focus when the dialog is opened.
By default, focus moves to the first tabbable element inside the popup, except when the dialog
is opened by touch — then the popup itself is focused to avoid opening the virtual keyboard.
- false: Do not move focus.
- true: Move focus based on the default behavior (first tabbable element or popup).
- RefObject: Move focus to the ref element.
- function: Called with the interaction type (mouse, touch, pen, or keyboard).
Return an element to focus, true to use the default behavior, null to fall back to the default behavior, or false/undefined to do nothing. |
| finalFocus | boolean | React.RefObject<HTMLElement | null> | ((closeType: InteractionType) => boolean | HTMLElement | null | void) | undefined | – | Determines the element to focus when the dialog is closed.
- false: Do not move focus.
- true: Move focus based on the default behavior (trigger or previously focused element).
- RefObject: Move focus to the ref element.
- function: Called with the interaction type (mouse, touch, pen, or keyboard).
Return an element to focus, true to use the default behavior, null to fall back to the default behavior, or false/undefined to do nothing. |
| className | string | ((state: State) => string | undefined) | undefined | – | CSS class applied to the element, or a function that returns a class based on the component's state. |
| render | React.ReactElement | ComponentRenderFn<RenderFunctionProps, State> | undefined | – | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.
Accepts a ReactElement or a function that returns the element to render. |
| style | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) | undefined | – | Style applied to the element, or a function that returns a style object based on the component's state. |
Also takes every attribute of Primitive.Popup.Props.
| Prop | Type | Default | Description |
|---|---|---|---|
| motion | boolean | undefined | – | Enable token-based transitions; false disables motion. |
| forceRender | boolean | undefined | – | Whether the backdrop is forced to render even when nested. |
| className | string | ((state: State) => string | undefined) | undefined | – | CSS class applied to the element, or a function that returns a class based on the component's state. |
| render | React.ReactElement | ComponentRenderFn<RenderFunctionProps, State> | undefined | – | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.
Accepts a ReactElement or a function that returns the element to render. |
| style | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) | undefined | – | Style applied to the element, or a function that returns a style object based on the component's state. |
Also takes every attribute of Primitive.Backdrop.Props.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | ((state: State) => string | undefined) | undefined | – | CSS class applied to the element, or a function that returns a class based on the component's state. |
| render | React.ReactElement | ComponentRenderFn<RenderFunctionProps, State> | undefined | – | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.
Accepts a ReactElement or a function that returns the element to render. |
| style | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) | undefined | – | Style applied to the element, or a function that returns a style object based on the component's state. |
Also takes every attribute of Primitive.Title.Props.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | ((state: State) => string | undefined) | undefined | – | CSS class applied to the element, or a function that returns a class based on the component's state. |
| render | React.ReactElement | ComponentRenderFn<RenderFunctionProps, State> | undefined | – | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.
Accepts a ReactElement or a function that returns the element to render. |
| style | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) | undefined | – | Style applied to the element, or a function that returns a style object based on the component's state. |
Also takes every attribute of Primitive.Description.Props.
Do
Don't
Use the named parts for keyboard and focus behavior.
Related
- Component API: naming, state, composition and compatibility.
- Interaction states: focus, disabled and selected presentation.
- Form field: the assembled label and validation recipe.