ConfirmationDialog
A SwiftUI ConfirmationDialog component for presenting confirmation prompts.
Expo UI ConfirmationDialog matches the official SwiftUI confirmationDialog API and presents an action sheet-style dialog with a title, actions, and an optional message.
Usage
Basic confirmation dialog
Use ConfirmationDialog.Trigger to define the visible element and ConfirmationDialog.Actions to provide the dialog buttons.
import { useState } from 'react';
import {
Host,
ConfirmationDialog,
Button,
} from '@expo/ui/swift-ui';
export default function BasicConfirmationDialogExample() {
const [isPresented, setIsPresented] = useState(false);
return (
<Host style={{ flex: 1 }}>
<ConfirmationDialog
title="Are you sure?"
isPresented={isPresented}
onIsPresentedChange={setIsPresented}
titleVisibility="visible">
<ConfirmationDialog.Trigger>
<Button
label="Show dialog"
onPress={() => setIsPresented(true)}
/>
</ConfirmationDialog.Trigger>
<ConfirmationDialog.Actions>
<Button
label="Confirm"
onPress={() => setIsPresented(false)}
/>
<Button label="Cancel" role="cancel" />
</ConfirmationDialog.Actions>
</ConfirmationDialog>
</Host>
);
}
Destructive action confirmation
Use role="destructive" on a Button inside ConfirmationDialog.Actions to style it as a destructive action.
import { useState } from 'react';
import {
Host,
ConfirmationDialog,
Button,
Text,
} from '@expo/ui/swift-ui';
export default function DestructiveConfirmationDialogExample() {
const [isPresented, setIsPresented] = useState(false);
return (
<Host style={{ flex: 1 }}>
<ConfirmationDialog
title="Delete Item?"
isPresented={isPresented}
onIsPresentedChange={setIsPresented}
titleVisibility="visible">
<ConfirmationDialog.Trigger>
<Button
label="Delete"
role="destructive"
onPress={() => setIsPresented(true)}
/>
</ConfirmationDialog.Trigger>
<ConfirmationDialog.Actions>
<Button
label="Delete"
role="destructive"
onPress={() => {
console.log('Deleted');
setIsPresented(false);
}}
/>
<Button label="Cancel" role="cancel" />
</ConfirmationDialog.Actions>
<ConfirmationDialog.Message>
<Text>This action cannot be undone.</Text>
</ConfirmationDialog.Message>
</ConfirmationDialog>
</Host>
);
}
With message and multiple actions
Use ConfirmationDialog.Message to display a descriptive message below the title, and include multiple action buttons for different choices.
import { useState } from 'react';
import {
Host,
ConfirmationDialog,
Button,
Text,
} from '@expo/ui/swift-ui';
export default function MultiActionConfirmationDialogExample() {
const [isPresented, setIsPresented] = useState(false);
return (
<Host style={{ flex: 1 }}>
<ConfirmationDialog
title="Save Changes?"
isPresented={isPresented}
onIsPresentedChange={setIsPresented}
titleVisibility="visible">
<ConfirmationDialog.Trigger>
<Button
label="Close document"
onPress={() => setIsPresented(true)}
/>
</ConfirmationDialog.Trigger>
<ConfirmationDialog.Actions>
<Button
label="Save"
onPress={() => console.log('Saved')}
/>
<Button
label="Discard"
role="destructive"
onPress={() => console.log('Discarded')}
/>
<Button label="Cancel" role="cancel" />
</ConfirmationDialog.Actions>
<ConfirmationDialog.Message>
<Text>
You have unsaved changes. What would you like to do?
</Text>
</ConfirmationDialog.Message>
</ConfirmationDialog>
</Host>
);
}
Hidden title
Set titleVisibility="hidden" to hide the dialog title while still showing the actions and message. You should still provide a title for accessibility.
import { useState } from 'react';
import {
Host,
ConfirmationDialog,
Button,
Text,
} from '@expo/ui/swift-ui';
export default function HiddenTitleConfirmationDialogExample() {
const [isPresented, setIsPresented] = useState(false);
return (
<Host style={{ flex: 1 }}>
<ConfirmationDialog
title="Hidden Title"
isPresented={isPresented}
onIsPresentedChange={setIsPresented}
titleVisibility="hidden">
<ConfirmationDialog.Trigger>
<Button
label="Show dialog"
onPress={() => setIsPresented(true)}
/>
</ConfirmationDialog.Trigger>
<ConfirmationDialog.Actions>
<Button
label="OK"
onPress={() => setIsPresented(false)}
/>
<Button label="Cancel" role="cancel" />
</ConfirmationDialog.Actions>
<ConfirmationDialog.Message>
<Text>Only the message and actions are visible.</Text>
</ConfirmationDialog.Message>
</ConfirmationDialog>
</Host>
);
}
API
import { ConfirmationDialog } from '@expo/ui/swift-ui';Component
ConfirmationDialog
Type: React.Element<ConfirmationDialogProps>
ConfirmationDialog presents a confirmation dialog with a title, optional message, and action buttons.
Props of the ConfirmationDialog component.
ConfirmationDialogProps
children
Type: ReactNode
The contents of the confirmation dialog. Should include ConfirmationDialog.Trigger, ConfirmationDialog.Actions, and optionally ConfirmationDialog.Message.
isPresented
Optional • Type: boolean
Whether the confirmation dialog is presented.
onIsPresentedChange
Optional • Type: (isPresented: boolean) => void
A callback that is called when the isPresented state changes.
title
Type: string
The title of the confirmation dialog.
titleVisibility
Optional • Literal type: string • Default: 'automatic'
The visibility of the dialog title.
Acceptable values are: 'automatic' | 'hidden' | 'visible'
Inherited props
Modifiers
Use these modifiers in the modifiers prop of the SwiftUI version.
Expo UI lets you put any of the 89 modifiers for any view on ConfirmationDialog, but not all of them do something here.
- 74 change what you see on ConfirmationDialog.
- 2 work, but not in the way that you may expect.
- 2 have no visible effect on ConfirmationDialog.
- 13 work only in one place, such as a widget or a
Grid.
Where the modifiers go
modifiers apply to the ConfirmationDialog.Trigger view. They do not change the dialog, because the system draws it. With no trigger, you see no result.
Best modifiers for ConfirmationDialog
These modifiers are the ones that you use most with ConfirmationDialog.
Also works on ConfirmationDialog
ConfirmationDialog takes these modifiers too, and each one works in the usual way.
accessibilityAddTraitsaccessibilityElementaccessibilityHiddenaccessibilityHintaccessibilityIdentifieraccessibilityInputLabelsaccessibilityLabelaccessibilityRemoveTraitsaccessibilityValueallowsTighteninganimationaspectRatiobackgroundbackgroundOverlayblurboldborderbrightnessclippedclipShapecolorInvertcontainerRelativeFrameiOS 17+containerShapecontentShapecontentTransitioniOS 16+contrastcornerRadiusdynamicTypeSizeenvironmentfixedSizefontforegroundColorforegroundStylegeometryGroupiOS 17+glassEffectgrayscalehueRotationidignoreSafeAreaimageScaleitalickerninglineHeightiOS 26+lineLimitlineSpacingluminanceToAlphamaskminimumScaleFactormonospacedDigitmultilineTextAlignmentoffsetonGeometryChangeonLongPressGestureonTapGestureopacityoverlayredactedrotation3DEffectrotationEffectsaturationscaleEffectshadowstrikethroughstrokeBordertextCasetinttruncationModeunderline
Needs care on ConfirmationDialog
These modifiers work on ConfirmationDialog, but not in the way that you may expect.
| Modifier | What to know |
|---|---|
onAppear | Runs for the trigger, not for the dialog. |
onDisappear | Runs for the trigger, not for the dialog. |
No visible effect on ConfirmationDialog
ConfirmationDialog accepts these modifiers, but you see no change. They do not give an error.
| Modifier | Why nothing happens |
|---|---|
layoutPriority | It has an effect only when the view shares an axis with other views in a stack. |
zIndex | It changes the order of views that cover each other in the same parent, and ConfirmationDialog does not stack its children. |
Only in some places
These modifiers work only in a widget, in a Grid, in a Namespace or in a parent that asks for them.
| Modifier | Where it works |
|---|---|
activityBackgroundTint | Works only in a Live Activity. It has no effect in the app. |
alignmentGuide | Has an effect only when the parent, such as a VStack or ZStack, aligns its children by the same guide. |
containerBackground | Works only in a widget, or in a navigation container when you use a navigation placement. |
glassEffectId | Works only on a view that also has glassEffect, in a GlassEffectContainer and a Namespace. |
gridCellAnchor iOS 16+ | Works only on a cell of a Grid. Grid is in @expo/ui/swift-ui, but it has no Expo docs page. |
gridCellColumns | Works only on a view in a Grid.Row. Grid is in @expo/ui/swift-ui, but it has no Expo docs page. |
gridCellUnsizedAxes | Works only on a view in a Grid. Grid is in @expo/ui/swift-ui, but it has no Expo docs page. |
gridColumnAlignment iOS 16+ | Works only on a view in a Grid.Row. Grid is in @expo/ui/swift-ui, but it has no Expo docs page. |
invalidatableContent iOS 17+ | Has an effect only when a parent view uses redacted with the invalidated reason. |
matchedGeometryEffect | Works only in a Namespace. Give two views the same id and change between them with an animation. |
privacySensitive | Has an effect only when a parent view uses redacted with the privacy reason. |
unredacted | Has an effect only in a parent view that uses redacted. |
widgetURL | Works only in a widget. It has no effect in the app. |
Sources
The original Expo docs for this page:
- ConfirmationDialog (SwiftUI) (
source-of-truth/versions/v57.0.0/sdk/ui/swift-ui/confirmationdialog.md)



