Dialog
Pre-alphaThe registry and the CLI are not published yet.Roadmap

Dialog

Compound confirmation modal.

Drafts

Launch announcementEdited 2h ago
Q3 letterEdited yesterday
Delete this draft?

“Launch announcement” will be deleted. You can’t undo this.

Cancel

Delete

Installation

npx axiom add dialog
pnpm dlx axiom add dialog
yarn dlx axiom add dialog
bun x axiom add dialog

Also copies: portal, overlay, button, use-overlay-back-handler, which closes the dialog on a back action (Android back button, and with a navigator the back gesture and header back button). See navigation.

Installs: react-native-reanimated, react-native-worklets.

The open state and the enter and exit animation live in use-dialog.ts. The surface color comes from dialog.default.default.background in the component tokens.

Usage

import { Dialog } from "@/components/ui/dialog";

<Dialog.Root open={open} onOpenChange={setOpen}>
	<Dialog.Trigger asChild>
		<Button variant="ghost">Delete</Button>
	</Dialog.Trigger>
	<Dialog.Content>
		<Dialog.Title>Delete this draft?</Dialog.Title>
		<Dialog.Description>You can't undo this.</Dialog.Description>
		<Dialog.Actions>
			<Dialog.Cancel>Cancel</Dialog.Cancel>
			<Dialog.Action destructive onPress={remove}>
				Delete
			</Dialog.Action>
		</Dialog.Actions>
	</Dialog.Content>
</Dialog.Root>;

Props

Dialog.Root

PropTypeDefaultDescription
openbooleanControlled visibility.
defaultOpenbooleanfalseInitial visibility when the dialog manages its own state.
onOpenChange(open: boolean) => voidCalled when the dialog opens or closes.
childrenReactNodeTrigger and Content.

Dialog.Trigger

PropTypeDefaultDescription
asChildbooleanfalseUses the child as the trigger.

It also accepts every Tappable prop.

Dialog.Content

PropTypeDefaultDescription
dismissiblebooleantrueCloses on backdrop press and Android back. false when the user must pick an action.
mediaReactNodeIcon or illustration above the title.
widthnumber290Dialog width, capped by the screen margins.
onDismiss() => voidCalled after the close animation.
childrenReactNodeTitle, description, custom content, actions.
styleStyleProp<ViewStyle>Extra styles for the dialog surface.

Focus moves into the dialog when it opens and returns to the trigger when it closes. Screen readers can’t reach the screen behind it.

Dialog.Title, Dialog.Description

PropTypeDefaultDescription
childrenReactNodeTitle: the question, in a few words. Description: the consequence. Both are announced when the dialog opens.

Dialog.Actions

PropTypeDefaultDescription
orientation'horizontal' | 'vertical''horizontal'horizontal for two short actions, vertical for three actions or long labels.
childrenReactNodeDialog.Cancel and Dialog.Action.

Dialog.Action, Dialog.Cancel

Button props, plus:

PropTypeDefaultDescription
destructivebooleanfalseOn Action: red solid button, for irreversible actions.
closeOnPressbooleantrueCloses the dialog after onPress. Set to false with an async onPress and loading to keep it open while it runs.

Dialog.Cancel is an outline button that closes the dialog; it is also what a back action triggers.

Use cases

Confirm an irreversible action

State what will be lost, and name the action with the verb, not “OK”.

Remove Grace from the team?

She’ll lose access to 12 shared projects.

Cancel

Remove

<Dialog.Content>
	<Dialog.Title>Remove {member.firstName} from the team?</Dialog.Title>
	<Dialog.Description>
		They'll lose access to {count} shared projects.
	</Dialog.Description>
	<Dialog.Actions>
		<Dialog.Cancel>Cancel</Dialog.Cancel>
		<Dialog.Action destructive onPress={() => removeMember(member.id)}>
			Remove
		</Dialog.Action>
	</Dialog.Actions>
</Dialog.Content>

Unsaved changes

Three choices stacked vertically, the safe one at the bottom. discard can leave the screen with router.back(): the dialog closes and the navigation goes through (see useOverlayBackHandler).

Save changes?

You edited the event title and time.

Save

Discard

Keep editing

<Dialog.Content dismissible={false}>
	<Dialog.Title>Save changes?</Dialog.Title>
	<Dialog.Actions orientation="vertical">
		<Dialog.Action onPress={save}>Save</Dialog.Action>
		<Dialog.Action variant="ghost" destructive onPress={discard}>
			Discard
		</Dialog.Action>
		<Dialog.Cancel>Keep editing</Dialog.Cancel>
	</Dialog.Actions>
</Dialog.Content>

Action that takes time

closeOnPress={false} with loading: the dialog stays until the request succeeds, and shows an error in place if it fails.

Sign out of all devices?

You’ll need to sign in again on each one.

Cancel

<Dialog.Action
	closeOnPress={false}
	loading={mutation.isPending}
	onPress={async () => {
		await mutation.mutateAsync();
		setOpen(false);
	}}
>
	Sign out
</Dialog.Action>

When to use it

A dialog interrupts the user. Keep it for decisions that need an answer before going further, such as confirming a deletion. For choosing among options, a BottomSheet or a Menu keeps more context.