SwiftUI.List with Menu with Plain Button Style Breaks Event Loop
With Xcode 14.3.1 on macOS 13 (Ventura), I found that you cannot put SwiftUI.Menu
s inside List
s without breaking the key event loop – iff you also set the menu button’s .buttonStyle(.plain)
!
Once that button style is used, menu item interactions will make the app
- stop producing mouse tracking events (hover effects don’t work),
- stop reacting to Cmd+Tab to activate the app,
- stop reacting to keyboard events like Cmd+W.
Mouse clicks still go through, somewhat.
Curiously, while Cmd+W doesn’t immediately close the window in this state, clicking inside the app’s main menu still works, and once there, the shortcut is passed on.
Is there a private event tracking loop (for mouse events) that never finishes?
Will macOS 14, which uses native NSMenu
s (finally) fix this? (Can anyone test that with the beta?)
Reported as FB12285575.
Minimum reproducible app
This is enough to make the problem appear:
struct RowView: View {
@State var hovering = false
var body: some View {
HStack {
Text("Hello, world!")
Menu {
Button("Test 1") { }
Button("Test 2") { }
} label: {
Label("Menu", systemImage: "gear")
}
// .buttonStyle(.plain) // 👈 1️⃣ uncomment to make the app not receive events after selecting a menu item
}
.padding()
// Visualize that the app doesn't react to mouse movement (or key events, actually):
.border(hovering ? Color.blue : .clear)
.onHover { hovering = $0 }
}
}
@main
struct ListMenuTestApp: App {
var body: some Scene {
WindowGroup {
List { // 👈 2️⃣ Use `VStack` instead of `List` after uncommenting 1️⃣, then everything works again
ForEach((1...5), id: \.self) { _ in
RowView()
}
}
}
}
}
You can download a sample project from my openly shared FB12285575