TechnologiesSwiftUIPresentation and Dialogs

ContextMenu struct

iOSmacOStvOSwatchOSvisionOS✓ renders

A container for views that you present as menu items in a context menu.

How it works

A context menu is a pop-up list of actions that a view presents when the user invokes it directly — a long press on touch platforms, or a right-click on the Mac. Use ContextMenu to attach commands that act on a specific piece of content without those commands occupying permanent space in your layout, keeping the interface clean while still offering rich per-item operations. Reach for it whenever an element has secondary actions — like, share, delete, edit — that belong to that element rather than to the screen as a whole.

  1. Attach the menu with the contextMenu(menuItems:) modifier

    You rarely construct ContextMenu directly; instead you apply the .contextMenu modifier to the view that should respond, and SwiftUI builds the menu structure for you. The modifier takes a @ViewBuilder closure describing the menu's contents, and the view it decorates becomes the long-press (or right-click) target. Here .contextMenu hangs off the styled Text card, so that whole card is what the user presses to reveal the actions.

  2. Populate the menu with Button rows

    Each command in the menu is an interactive control — most commonly a Button whose action runs when the user selects that row. Inside the menu closure, two Buttons are declared: one toggles liked = true and the other resets liked = false, so choosing a row both dismisses the menu and mutates the view's state.

  3. Give each item a Label for text and an icon

    A menu row reads best with both a title and a glyph, which is exactly what Label provides via its label: builder. The example pairs Label("Like", systemImage: "heart") and Label("Remove", systemImage: "trash"), so SwiftUI renders each command with its SF Symbol alongside the text in the standard menu style.

  4. Signal intent with the Button role parameter

    The role: parameter lets the system style and order a command according to its meaning rather than you styling it by hand. Marking the second button Button(role: .destructive) tells SwiftUI it removes content, so the platform tints "Remove" to flag it as a deletion within the menu.

  5. Drive the surrounding view from the menu's actions

    Because the menu's buttons run ordinary closures, they can update any state the enclosing view observes. Both rows write to the @State property liked, and the Text reads that same value, so the card's caption flips between "Liked ♥" and "Long-press me" the moment a menu command fires.

Try it — Add a third Button inside the .contextMenu closure — for example one wrapping a Label("Share", systemImage: "square.and.arrow.up") — and watch a new row appear in the popped-up menu without changing the card itself.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

ContextMenu.swift
struct ContextMenuDemo: View {
    @State private var liked = false
    var body: some View {
        VStack(spacing: 12) {
            Text(liked ? "Liked ♥" : "Long-press me")
                .font(.headline)
                .padding()
                .background(Color.blue.opacity(0.15))
                .cornerRadius(10)
                .contextMenu {
                    Button {
                        liked = true
                    } label: {
                        Label("Like", systemImage: "heart")
                    }
                    Button(role: .destructive) {
                        liked = false
                    } label: {
                        Label("Remove", systemImage: "trash")
                    }
                }
        }
        .padding()
    }
}
Live preview
Long-press me
Long-press me
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →