Greetings, traveler!
Menus in SwiftUI are often used for quick, one-off commands: select an option, trigger an action, and you’re done. But what if you want a menu to behave less like a simple picker and more like a mini settings panel, where users can toggle multiple options in sequence before committing a final choice? By default the menu closes as soon as the user taps an item, but with the right API you can change this behaviour.
Rethinking the Menu Workflow
Typically, when you attach a Menu to a label — say a three-dots icon or a button — each tap inside the menu executes the action and immediately dismisses the menu. That is the expected “choose and close” workflow.
But there are scenarios where you might prefer a different interaction model:
- A menu that allows multiple toggles before.
- A menu that holds persistent state while the user navigates through a set of options.
- A menu that stays open while the user tries different settings, perhaps previewing the effect live, and only closes once they’re satisfied.
In those cases, the default dismissal behaviour is not ideal.
Customising Dismiss-Behaviour with menuActionDismissBehavior(_:)
SwiftUI extends menus with the modifier menuActionDismissBehavior(_:). This gives you fine control over whether taps inside the menu should cause it to dismiss or remain open.
The modifier takes a single parameter of type MenuActionDismissBehavior, which is an enum defined roughly as follows:
public enum MenuActionDismissBehavior {
case automatic // system-default behaviour
case enabled // explicitly force dismissal on each tap
case disabled // keep the menu open after taps
}Applying the modifier looks like this:
Menu("Options") {
Button("Toggle A") { /* … */ }
Button("Toggle B") { /* … */ }
Divider()
Button("Done") { /* … */ }
}
.menuActionDismissBehavior(.disabled)With .disabled, the menu stays open after each action, allowing the user to perform multiple actions before deciding to close it.
Illustrative Example: Batch Toggles
Imagine you have a set of features that a user can enable or disable, and you want the user to make multiple choices from the menu before closing it.
struct FeatureToggleMenu: View {
@State private var featureA = false
@State private var featureB = false
@State private var featureC = false
var body: some View {
Menu {
Section {
Toggle("Feature A", isOn: $featureA)
Toggle("Feature B", isOn: $featureB)
Toggle("Feature C", isOn: $featureC)
}
.menuActionDismissBehavior(.disabled)
Button("Apply Changes") {
// commit logic here
}
} label: {
Label("Settings", systemImage: "gearshape")
}
}
}In this layout:
- The user opens “Settings” and toggles various features without the menu closing each time a toggle is tapped.
- After making choices, they hit “Apply Changes” and then can close the menu (depending on implementation).
- You can even manually force closure by using a dedicated “Done” button.
Conclusion
The menuActionDismissBehavior(_:) modifier is a convenient API for transforming typical SwiftUI menus into more robust mini-interfaces for settings, toggles, and multi-step workflows. Using this thoughtfully can lead to cleaner, more intuitive UX when you need more than a simple “choose and done” interaction.
