How to show UIMenu from UIButton or UIBarButtonItem

Learn how to display context / popup menu from UIBarButtonItem and UIButton with this guide.

UIMenu is great new way to provide user with on-demand inline options. Since iOS 13 we could show these menus from TableView and CollectionView cells by implementing one delegate method.

With iOS 14 these menus are getting ever more useful with the option of showing them from UIBarButtons and UIButtons. The UIBarButton use-case is a bit easier, so start with that.

Example UIMenu

Let's start with example menu definition:

var menuItems: [UIAction] {
    return [
        UIAction(title: "Standard item", image: UIImage(systemName: "sun.max"), handler: { (_) in   
        }),
        UIAction(title: "Disabled item", image: UIImage(systemName: "moon"), attributes: .disabled, handler: { (_) in 
        }),
        UIAction(title: "Delete..", image: UIImage(systemName: "trash"), attributes: .destructive, handler: { (_) in  
        })
    ]
}

var demoMenu: UIMenu {
    return UIMenu(title: "My menu", image: nil, identifier: nil, options: [], children: menuItems)
}

Because this is an example, I left the handlers empty.

UIBarButtonItem with UIMenu

Next we can move to the UIBarButtonItem definition:

navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Menu", image: nil, primaryAction: nil, menu: demoMenu)

Since we haven't specified the primaryAction, the menu will appear immediately after tap.

UIMenu from UIBarButtonItem

UIButton + UIMenu

With buttons it is a little bit more complicated. If you want your UIMenu to appear immediately, you need to set the showsMenuAsPrimaryAction to true, otherwise the menu will appear after long press.

@IBOutlet var showMenuButton: UIButton!

func configureButtonMenu() {
    showMenuButton.menu = demoMenu
    showMenuButton.showsMenuAsPrimaryAction = true
}

With this setup code, after you tap the button, the menu will be automatically presented. Note that there is currently no init variant for UIButton that let's you specify pass the menu as a parameter.

UIMenu from UIButton

I found that this works very well as a replacement where you would traditionally use UIAlertController in the .actionSheet configuration. You don’t have to worry about which UIViewController is going to present the menu and there is no need to set the popover anchor when on iPad. That is a big win.

Uses: Xcode 12 & Swift 5.3

Filip Němeček profile photo

WRITTEN BY

Filip Němeček @nemecek_f

iOS blogger and developer with interest in Python/Django. Telling other devs' stories with iOS Chat.