NEW: Learn SwiftUI with my free YouTube video series! >>

How do you show a modal view controller when a UITabBarController tab is tapped?

Swift version: 5.0

Paul Hudson    @twostraws   

Usually tapping a tab in a UITabBar shows that tab, but it's often the case that you want to override that behavior, for example to show a view modally. If you're using one of Xcode's built-in storyboard templates for creating your user interface, it's not immediately obvious how to do this, but fortunately it's not so hard using the approach below.

First, find the viewDidLoad() method for your initial view controller – whichever one is shown first in your app. Now add this code to it:

self.tabBarController?.delegate = UIApplication.shared.delegate as? UITabBarControllerDelegate

That sets up your application delegate (in AppDelegate.swift) to handle events from the tab bar controller. This line uses optionals safely, so it will do nothing if you change your app structure later.

Now open AppDelegate.swift, and add UITabBarControllerDelegate to the list of protocols your app delegate conforms to, like this:

class AppDelegate: UIResponder, UIApplicationDelegate, UITabBarControllerDelegate {

Finally, you should implement the shouldSelect method on your app delegate, which must return true or false depending on whether you want the regular tab behavior (return true) or your own (return false).

In the example below, I want the regular view controller behavior for all tabs unless the user is trying to show one with the class YourViewController. When that happens, I'll create a new view controller and show it modally instead:

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
    if viewController is YourViewController {
        if let newVC = tabBarController.storyboard?.instantiateViewController(withIdentifier: "YourVCStoryboardIdentifier") {
            tabBarController.present(newVC, animated: true)
            return false

    return true

There are two things to note about that code. First, you'll need to give your view controller a storyboard identifier so that instantiateViewController(withIdentifier:) will work. Second, this won't have any extra performance impact on your code – the view that would have been shown wasn't created yet, so creating a new one here won't be duplicating any work.

SPONSOR Meet the new Instabug – more than just bug reporting! We help you build better apps and minimize your debugging time. With each bug report, we automatically capture details like network requests, repro steps, and session details. Get real-time crash reports with stack trace details and session data to help you catch and fix issues easily. And with our customizable in-app surveys, you’ll gather insightful user feedback and much more. Instabug is the fastest and easiest way to release with confidence. Start your free trial now! Start your free trial now!

Available from iOS 7.0

Did this solution work for you? Please pass it on!

Other people are reading…

About the Swift Knowledge Base

This is part of the Swift Knowledge Base, a free, searchable collection of solutions for common iOS questions.

Buy Testing Swift Buy Practical iOS 12 Buy Pro Swift Buy Swift Design Patterns Buy Swift Coding Challenges Buy Server-Side Swift (Vapor Edition) Buy Server-Side Swift (Kitura Edition) Buy Hacking with macOS Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with Swift Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let me know!

Average rating: 4.0/5

Click here to visit the Hacking with Swift store >>