SwiftUI Menu and Context Menu: Buttons with Dropdown Lists

Creating an intuitive and user-friendly interface is crucial for success in the app development world. With SwiftUI menus, you can now easily achieve this goal by displaying secondary actions in a compact and organized manner. Menus are interactive components designed to save space and declutter the app’s interface. SwiftUI menus are special buttons, you can learn see how buttons work in this post.

This blog post will explore SwiftUI menus, their benefits, and how they can be implemented effectively. 

Some common use cases for menus include

  • Disambiguation: Clarifying user choices when performing an action, such as selecting a specific item to add to the Photos app.
In Photos app you can use the
In Photos app you can use the “plus” button to choose from a different options to add albums, folders or shared albums.
  • Navigation: Navigate through an app’s history or content, like browsing previously visited sites in Safari by tapping and holding the “back” button.
Pressing on the back button in Safari will directly navigate back to the last page. Long press will display the browsing history.
Pressing on the back button in Safari will directly navigate back to the last page. Long press will display the browsing history.
  • Selection: Making a selection among multiple options, as seen in the Podcasts app where users can tap the “Sort” button to choose a sorting method.
In the Podcast app you can use a menu picker to sort your music.
In the Podcast app you can use a menu picker to sort your music.
  • Displaying secondary options: Present additional actions that are not frequently used but still easily accessible, such as the “more” button in the Files app.
Files app for iOS 13 had multiple buttons scattered over the user interface. The iOS 14 redesign uses the more button to show all secondary actions. This makes the UI more clean and easy to use.
Files app for iOS 13 had multiple buttons scattered over the user interface. The iOS 14 redesign uses the more button to show all secondary actions. This makes the UI more clean and easy to use.

By incorporating menus into your SwiftUI app, you can ensure a more organized and efficient user interface that effectively displays secondary actions without overwhelming users. Stay tuned as we dive deeper into the world of SwiftUI menus and explore how to implement all these different use cases.

If you want to learn more about best practices for menus, watch the Design with iOS pickers, menus and actions presentation from WWDC 2020. The examples above are from this talk.

SwiftUI Popup Menu Button

SwiftUI makes it simple to create menu buttons with just a few lines of code. In this section, we’ll demonstrate how to implement a SwiftUI menu button. If you want to reproduce the Photos app example from above. This menu button will show dropdown options for creating albums, shared albums or folders:

struct ContentView: View {
    var body: some View {
        Menu {
            Button {
            } label: {
                Label("New Album", systemImage: "rectangle.stack.badge.plus")
            }
            Button {
            } label: {
                Label("New Folder", systemImage: "folder.badge.plus")
            }
            Button {
            } label: {
                Label("New Shared Album", systemImage: "rectangle.stack.badge.person.crop")
            }
        } label: {
            Label("Add New", systemImage: "plus")
        }
    }
}

You can also create a Menu with a secondary action. This was used in the Safari app for the back button:

Menu("menus with long press") {
    Button("first") { }
    Button("second") { }
    Button("last") { }
} primaryAction: {
   // execute primary action
}

If the user taps on the button, the primary action is executed. However when the user long press, the menu list is shown.

Organising the list of buttons inside menus

The appearance of the buttons inside the menu button list, is defined by the system. Apple recommends to show icons for all buttons.

One option is to use a button role of destructive. This will make the button have a red foreground color. This should be used for a delete button:

Menu {
    Button("first") {  }
    Button("second") {  }
    Button("Delete", role: .destructive) {  }
} label: {
    Label("Menu", systemImage: "ellipsis.circle")
}

Long lists of buttons can become unreadable. You can add sections and dividers inside the Menu list to make them more organized:

Menu {
    Section("Primary Actions") {
        Button("First") {  }
        Button("Second") {  }
    }

    Button {
        // Add this item to a list of favorites.
    } label: {
        Label("Add to Favorites", systemImage: "heart")
    }

    Divider()

    Button(role: .destructive) {
    } label: {
        Label("Delete", systemImage: "trash")
    }
} label: {
    Label("Menu", systemImage: "ellipsis.circle")
}
Adding a Menu inside a toolbar item with a long list of options.
Adding a Menu inside a toolbar item with a long list of options.

In order to replicate the Files app example from above, you can place the Menu inside a ToolbarItem:

struct ContentViewView: View {
    var body: some View {
        NavigationView {
            Text("Something important to show")
                .padding()
                .navigationTitle("Menu")
                .toolbar {
                    ToolbarItem {
                        Menu {
                           ...
                        }
                    }
                }
        }
    }
}

You can also use submenus to organize better. The submenu will appear above the main menu:

Menu {
    Button("first") {  }
    Button("second") {  }
    Menu {
        Button("third") {  }
        Button("forth") {  }
    } label: {
        Label("More", systemImage: "folder.circle")
    }

    Button("Delete", role: .destructive) {
    }

} label: {
    Label("Menu", systemImage: "ellipsis.circle")
}
Free SwiftUI Layout Book

Get Hands-on with SwiftUI Layout.

Master SwiftUI layouts with real-world examples and step-by-step guide. Building Complex and Responsive Interfaces.

How to keep the menu list order?

A new feature for iOs 16 and macOS 13 is the menuOrder modifier.

Menu {
    Button("first") {  }
    Button("second") {  }
    ...
} label: {
    Label("Menu", systemImage: "ellipsis.circle")
}
.menuOrder(.fixed)

You have the following options

  • priority order keeps the first items closer to the user’s point of interaction
  • fixed order always orders items from top to bottom.
The default value is priority order style (left). You can change the fixed order for the menu (right).
The default value is priority order style (left). You can change the fixed order for the menu (right).

How to Customize the SwiftUI Menu Button Appearance

Because Menus are buttons with an extra dropdown view, you can style them like regular buttons. See how you can fully customize buttons in Mastering SwiftUI Buttons: A Comprehensive Guide to Creating and Customizing Buttons. For example, you can use the bordered button style like so:

Menu("bordered Menu") {
    Button("First") { }
    Button("Second") { }
}
.buttonStyle(.bordered)
Menu buttons with bordered and bordered prominent button style. When the menu is pressed the opacity is changed slightly to make it look pressed.
Menu buttons with bordered and bordered prominent button style. When the menu is pressed the opacity is changed slightly to make it look pressed.

MacOS specific Menu Styling

Menu looks quite different on macOS. Per default menus have a border and a menu indicator. To change the border style use menuStyle:

Menu("Menu borderless button style") {
    ...
}
.menuStyle(.borderlessButton)

In order to hide the menu indicator, you can use the menuIndicator modifier:

Menu("Menu indicator hidden") {
    ...
}
.menuIndicator(.hidden)
On macOS menus are very typical. Here are differently styled menus with and without borders and without the menu indicator.
On macOS menus are very typical. Here are differently styled menus with and without borders and without the menu indicator.

How to create a selection Menu with Picker

If you want to allow the user to select from a list of predefined options, like sorting in the Podcast app, it is best to use a Picker. Picker has a style that will make it look like a menu. Read about SwiftUI Picker Made Easy: Tutorial With Example.

Let’s recreate the example and start with an enum data definition for Sorting:

enum AlbumSorting: String, CaseIterable, Identifiable {
    case title
    case recentlyAdded
    case artist
    var id: Self { return self }

    var title: String {
        switch self {
            case .title:
                return "Title"
            case .recentlyAdded:
                return "Recently Added"
            case .artist:
               return "Artist"
        }
    }
}

Showing a picker with the menu style can be done with the following example code:


struct ExampleView: View {
    @State private var selectedSorting = AlbumSorting.artist
    var body: some View {
        Picker("Sort", selection: $selectedSorting) {
            ForEach(AlbumSorting.allCases) {
                Text($0.title)
                  .tag($0)
            }
        }
        .pickerStyle(.menu)
    }
}

It shows the selected item. For the Album app example, we want to show something different. The can be done by embedding the picker inside a menu like so:

Menu {
    Picker("Sort", selection: $selectedSorting) {
        ForEach(AlbumSorting.allCases) {
            Text($0.title)
        }
    }
} label: {
    Text("Sort")
}
Picker with a menu style (middle) and inside a menu (right).
Picker with a menu style (middle) and inside a menu (right).

SwiftUI contextMenu to create dropdown menu to any view

How to create context menu in Swift?

To use a context menu in SwiftUI, attach the .contextMenu modifier to the view you want the context menu to be associated with. Inside the context menu modifier, add Button views for each option you want to include in the context menu. Here’s an sample code with an image:

Image("candies")
    .resizable()
    .scaledToFit()
    .frame(width: 200)
    .contextMenu {
        Button {
            print("action for context menu item 1")
        } label: {
            Label("First", systemImage: "icon_name")
        }
        // Additional context menu items
    }
You can add a context menu to any view. For example, you can add it to a text or image view. The background for the whole screen is dimmed out.
You can add a context menu to any view. For example, you can add it to a text or image view. The background for the whole screen is dimmed out.

It is very common to right-click on a list or table item on macOS. The following is an example with a table. When you right-click on a row, a blue border is created around the selected row together with the menu.

Table(of: InventoryItem.self) {
    TableColumn("Name", value: \.name)
    TableColumn("Partnumber", value: \.partNumber)
    TableColumn("Quantity") { item in
        Text(String(item.quantity))
    }
} rows: {
    ForEach(items) { item in
        TableRow(item)
            .contextMenu {
                Button("Add To Shopping List") {  }
                Button("Quick Buy") {  }
                Button("Request Larger Number") { }
            }
    }
}
Context menu is very important for macOS, where the user has to right click to show the menu options.
Context menu is very important for macOS, where the user has to right click to show the menu options.

Conclusion

SwiftUI menus and context menus provide an efficient and compact way to organize secondary actions and options in your application. By understanding their use cases and implementation, you can create a more user-friendly and organized interface for your app. As we’ve explored in this blog post, implementing menus and context menus in SwiftUI is straightforward and versatile, allowing you to cater to various user interactions and adapt to different device types. Utilize these powerful components in your SwiftUI app to enhance the user experience and streamline your app’s functionality.

FAQ

What is the menu in button SwiftUI?

The menu in button SwiftUI refers to a menu that is triggered by tapping on a button in a SwiftUI application. This menu is used to display secondary actions or choices related to the button, providing a compact and efficient way to organize functionality in your app.

How do I add a menu in SwiftUI?

To add a menu in SwiftUI, use the Menu view and define the menu items as Button views inside the Menu. You also need to specify the menu button’s appearance using a Label view. Here’s an example:

Menu {
    Button {
        // action for menu item 1
    } label: {
        Label("Menu Item 1", systemImage: "icon_name")
    }
    // Additional menu items
} label: {
    Label("Menu Button", systemImage: "icon_name")
}

What is the difference between context menu and menu in SwiftUI?

In SwiftUI, a Menu is typically associated with a button and is activated when the button is tapped. It is used to display secondary actions or options related to the button. On the other hand, a context menu is associated with a specific view and is activated by long-pressing or right-clicking on the view. Context menus provide contextual options or actions related to the view they are attached to. Both menus and context menus can be created using similar components, such as Button and Label views, but their use cases and activation methods differ.

Further Reading

Leave a Comment

Subscribe to My Newsletter

Want the latest iOS development trends and insights delivered to your inbox? Subscribe to our newsletter now!

Newsletter Form

New Course Announcement!!!

50% OFF Launch Sale

MacOS Development with SwiftUI