Skip to content

fix(dialog): present dialogs from the topmost view controller on iOS - #2617

Open
theblang wants to merge 1 commit into
ionic-team:mainfrom
theblang:fix/dialog-present-from-topmost-vc
Open

theblang wants to merge 1 commit into
ionic-team:mainfrom
theblang:fix/dialog-present-from-topmost-vc

Conversation

@theblang

@theblang theblang commented Oct 20, 2026 •

Copy link
Copy Markdown

Closes #2404

The problem

On iOS, DialogPlugin presents every alert from bridge.viewController. If the app has another view controller presented over the web view, UIKit refuses the presentation, logs Attempt to present ... which is already presenting ..., and drops the alert. The action handlers never run, so the JS promise never settles.

Any native screen presented over the web view triggers it: the camera or photo picker, a QLPreviewController, the share sheet, the calendar edit sheet, or a sign-in sheet. The common case is an alert that a network response triggers while such a screen is open.

The fix

The 3 methods now present through one private present(_:for:). It walks presentedViewController from the bridge view controller to the topmost controller and presents from there. With nothing presented, the walk returns the bridge view controller, so the existing behaviour is unchanged.

The walk stops below a controller that isBeingDismissed. UIKit refuses a presentation from its presenter until that dismissal ends, and the refusal has no error path: present(_:animated:completion:) returns, logs a warning, and never runs the completion. The call would stay pending forever. In that window the plugin now rejects the call instead, the same way the Share plugin rejects when a share is already in progress.

#2574 applied the same walk to the Share plugin.

Testing

Tested in a Capacitor 8.5.3 app on an iPhone 18 Pro simulator, iOS 27:

  • With the photo picker open, Dialog.confirm shows above the picker and resolves on tap.
  • With nothing presented, Dialog.confirm behaves as before.
  • Dialog.alert and Dialog.prompt were not tested on a device. They use the same present(_:).

🤖 Generated with Claude Code

Present each alert from the topmost presented view controller instead of the bridge
view controller, so a dialog appears above any view controller the app has presented
over the web view. UIKit refuses to present from a view controller that already
presents one, and the refusal has no error path, so the call never resolved.

If the walk stops at a controller whose presented child is still being dismissed,
reject the call instead of leaving it pending.

Closes ionic-team#2404
@theblang
theblang force-pushed the fix/dialog-present-from-topmost-vc branch from 9174771 to ba9d72e Compare October 20, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[@capacitor/dialog] Dialog doesn't open when another Controller is Presenting

1 participant