In iOS, how to drag down to dismiss a modal?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
On modern iOS, drag-down dismissal for many modals is built in rather than something you always implement from scratch. If you present a view controller as a sheet, the system usually provides the interactive swipe-down gesture automatically. The real work is often deciding which presentation style you use and whether dismissal should be allowed, customized, or intercepted.
So the first question is not “how do I code the gesture?” but “am I using a modal presentation style that already supports interactive dismissal?” For standard sheets, the default platform behavior is often enough.
Use a Sheet Presentation First
If you present a controller with .pageSheet or .formSheet, iOS typically handles the drag-down dismissal gesture for you.
On current iOS versions, that often gives you the familiar sheet behavior automatically. If the presented controller has a sheetPresentationController, you can configure detents and appearance while keeping the built-in drag gesture.
This is the cleanest answer when a standard bottom sheet matches the design.
Control Whether the Modal Can Be Dismissed
Sometimes you want the sheet interaction but do not want users to dismiss it until they finish a task. In that case, use isModalInPresentation.
This keeps the modal onscreen even if the user tries to drag it down.
If you want to react when the user attempts dismissal, implement UIAdaptivePresentationControllerDelegate.
That is useful for unsaved changes flows where you need to prompt the user before allowing dismissal.
Use a Custom Interactive Transition Only for Custom Modals
If your modal uses .fullScreen or a completely custom presentation, the system may not provide sheet-style drag dismissal for free. In that case, you need your own pan gesture plus an interactive transition, typically driven by UIPercentDrivenInteractiveTransition.
A simplified pattern looks like this:
This example only triggers dismissal after a downward drag threshold. A full custom interactive transition is more complex, but the principle is the same: track drag progress, decide whether dismissal should finish, and drive the animation accordingly.
Prefer the System Gesture When It Fits
Custom interactive transitions are powerful, but they add complexity around gesture handling, animation progress, cancellation, and accessibility. If the modal can be a sheet, the system presentation is usually the better answer.
You should reach for a custom transition only when the design is clearly outside the standard sheet model, such as a bespoke card interaction or a full-screen modal that needs partial drag progress feedback.
Common Pitfalls
The most common mistake is building a custom pan-to-dismiss implementation when .pageSheet already provides the expected behavior.
Another issue is setting isModalInPresentation = true and then wondering why drag-down dismissal stopped working. That property is designed to prevent interactive dismissal.
A third problem is using .fullScreen and expecting sheet behavior automatically. Full-screen presentation often requires custom handling if you want the same gesture.
Summary
- For standard modals, prefer
.pageSheetor.formSheet, which usually provide drag-down dismissal automatically. - Use
sheetPresentationControllerto configure detents and sheet appearance. - Set
isModalInPresentationwhen dismissal should be blocked. - Use
UIAdaptivePresentationControllerDelegateto react to dismissal attempts. - Build a custom pan-driven transition only when the system sheet presentation does not match the design.

