Expo UI and Router for iOSExpo SDK 57 and later, iOS only
Components

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>
  );
}
A dialog anchored under the trigger, titled Are you sure? with a Confirm button
A dialog anchored under the trigger, titled Are you sure? with a Confirm button

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>
  );
}
A dialog titled Delete Item? with a message and a red Delete button
A dialog titled Delete Item? with a message and a red Delete button

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>
  );
}
A dialog titled Save Changes? with a message, a Save button, and a red Discard button
A dialog titled Save Changes? with a message, a Save button, and a red Discard button

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>
  );
}
A dialog showing only a message and an OK button, with no title
A dialog showing only a message and an OK button, with no title

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.

See: https://developer.apple.com/documentation/swiftui/view/confirmationdialog(_:ispresented:titlevisibility:actions:message:)

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.

Needs care on ConfirmationDialog

These modifiers work on ConfirmationDialog, but not in the way that you may expect.

ModifierWhat to know
onAppearRuns for the trigger, not for the dialog.
onDisappearRuns 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.

ModifierWhy nothing happens
layoutPriorityIt has an effect only when the view shares an axis with other views in a stack.
zIndexIt 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.

ModifierWhere it works
activityBackgroundTintWorks only in a Live Activity. It has no effect in the app.
alignmentGuideHas an effect only when the parent, such as a VStack or ZStack, aligns its children by the same guide.
containerBackgroundWorks only in a widget, or in a navigation container when you use a navigation placement.
glassEffectIdWorks 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.
gridCellColumnsWorks only on a view in a Grid.Row. Grid is in @expo/ui/swift-ui, but it has no Expo docs page.
gridCellUnsizedAxesWorks 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.
matchedGeometryEffectWorks only in a Namespace. Give two views the same id and change between them with an animation.
privacySensitiveHas an effect only when a parent view uses redacted with the privacy reason.
unredactedHas an effect only in a parent view that uses redacted.
widgetURLWorks only in a widget. It has no effect in the app.

Sources

The original Expo docs for this page:

On this page