Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: can you have a menu item with a checkmark and shortcut?

I'm writing a macOS app using SwiftUI, specifically, I'm adding a menu to the menu bar. The menu should have a selectable item -- item can have an optional checkmark in front of it -- and a shortcut. I cannot get it to work. It seems like you can either have a shortcut assigned -- you place a Button in the menu and attach the shortcut to the Button.

Button(String("Test")) {}
  .keyboardShortcut("1")

Or, you can have the item to be selectable -- you place a Button() into a Picker and set up the selection binding and the Button tag correctly.

Picker(selection: $selection) {
  Button(String("Test 1")) {}
    .tag(1)
}.pickerStyle(.inline)

But, not both. As soon as you put a Button with the shortcut into a Picker, the shortcut disappears.

Picker(selection: $selection) {
  Button(String("Test")) {}
    .keyboardShortcut("1") // << ignored
    .tag(1)
}.pickerStyle(.inline)

Am I missing something here or is this a known bug in SwiftUI? macOS 13.4.1, deployment target 12.0

like image 751
Anton Avatar asked Oct 16 '25 07:10

Anton


1 Answers

I don't think keyboard shortcuts on a Picker is currently supported. See also these related posts for people with similar situations: 1, 2.

As the first post says, you can use a bunch of Toggles instead, though you would have to handle updating the states of other toggles yourself, so that no two toggles are on at the same time.

Example:

struct ToggleState: Identifiable, Hashable {
    var isOn = false
    let id: Int
    let shortcut: KeyboardShortcut
}
@State var toggles = [
    ToggleState(isOn: true, id: 0, shortcut: .init("A")),
    ToggleState(id: 1, shortcut: .init("B")),
    ToggleState(id: 2, shortcut: .init("C")),
]

var body: some View {
    ForEach(Array(toggles.indices), id: \.self) { i in
        Toggle("\(toggles[i].id)", isOn: Binding(get: {
            toggles[i].isOn
        }, set: { _ in
            for j in toggles.indices {
                toggles[j].isOn = false
            }
            toggles[i].isOn = true
        }))
            .keyboardShortcut(toggles[i].shortcut)
    }
}
like image 168
Sweeper Avatar answered Oct 18 '25 23:10

Sweeper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!