Disable gesture to pull down form/page sheet modal presentation
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Starting with iOS 13, Apple changed the default modal presentation style to a card-like sheet that users can dismiss by swiping down. While this feels natural in many situations, there are cases where you need to prevent that gesture, for example when a user is filling out a multi-step form or confirming a destructive action. This article covers the practical ways to disable the pull-down dismiss gesture in UIKit and SwiftUI, with working code you can drop into your project.
How the Default Sheet Dismiss Works
When you call present(_:animated:completion:) on a view controller in iOS 13 and later, the system defaults to .automatic for modalPresentationStyle, which resolves to .pageSheet on most devices. The page sheet presentation includes a built-in interactive dismiss gesture: the user drags the sheet downward to close it.
Behind the scenes, UIKit attaches a UIPanGestureRecognizer to the presented view. The system's presentation controller watches for a downward drag and triggers dismissal when the velocity and distance thresholds are met.
Disabling Dismiss in UIKit
Using isModalInPresentation
The simplest and most reliable way to prevent swipe-to-dismiss is the isModalInPresentation property, introduced in iOS 13.
When isModalInPresentation is set to true, the user cannot dismiss the sheet by swiping down. They also cannot tap outside the sheet to dismiss it on iPad. The only way to close the modal is through an explicit action you provide, such as a Cancel or Done button.
Presenting the View Controller
Even with the grabber visible, the user can still drag between detent sizes (medium and large) but cannot dismiss the sheet by pulling it all the way down. The grabber serves as a visual indicator that the sheet supports resizing, which remains functional.
Using the Presentation Controller Delegate
For more granular control, you can implement UIAdaptivePresentationControllerDelegate. This lets you conditionally prevent dismissal based on the current state of your form.
The delegate approach is useful when you want to allow dismissal under certain conditions (for example, the form is empty) but block it when the user has entered data.
Disabling Dismiss in SwiftUI
SwiftUI provides the interactiveDismissDisabled modifier, available from iOS 15 onward.
You can also pass a boolean binding to conditionally enable or disable the gesture based on form state.
In this example, the sheet can be dismissed freely while the text field is empty, but once the user types something, the swipe gesture is disabled.
Handling iPad and Compact Height
On iPad, page sheets and form sheets appear as centered cards rather than full-screen overlays. Setting isModalInPresentation = true also prevents dismissal by tapping the dimmed area outside the sheet, which is the typical dismiss mechanism on iPad.
When a device is in compact height (iPhone in landscape), you may want the sheet to attach to the edges of the screen. Use prefersEdgeAttachedInCompactHeight on the sheet presentation controller for that layout, and isModalInPresentation still controls the dismiss behavior regardless of this setting.
Common Pitfalls
- Forgetting to set the
presentationController?.delegatebefore the view appears, which causes the delegate methods to never fire. - Setting
isModalInPresentationininit()instead ofviewDidLoad()or later. The presentation controller may not be available that early. - Not providing any dismiss button when you disable the gesture. Users will be stuck with no way to close the modal unless you add an explicit action.
- Confusing
isModalInPresentation(which prevents dismissal) withmodalPresentationStyle(which controls how the modal looks). - On SwiftUI, applying
interactiveDismissDisabledto the wrong view in the hierarchy. It must be applied inside the.sheetcontent closure, not on the presenting view.
Summary
Use isModalInPresentation = true in UIKit or .interactiveDismissDisabled(true) in SwiftUI to prevent the swipe-to-dismiss gesture on sheet modals. For conditional blocking based on form state, implement UIAdaptivePresentationControllerDelegate in UIKit or pass a boolean to interactiveDismissDisabled in SwiftUI. Always provide an explicit dismiss button so users are not trapped in a modal with no exit.

