iosmacosbuttonswiftuialert

Possible to have the enter / return key activate the "OK" button on a SwiftUI Alert with a textfield?


I have an Alert in my SwiftUI app:

.alert("Project Name:", isPresented: self.$alertPresented)
{
    TextField("", text: self.$userInput)
    /*.onSubmit
    {
        okButtonPushed()
        self.alertPresented = false
    }*/
    Button("Cancel", role: .cancel) { }
    Button("OK")
    {
        okButtonPushed()
    }
    .disabled(userInput.isEmpty)//.keyboardShortcut(.return)
}

It works fine as normal, but what I'm trying to do is make it so when the user hits the return or enter key on MacOS, it will be the same as if the user clicked the OK Button. I also want the OK Button to be highlighted so that it's clear to the user that they can hit return / enter to activate it.

I've tried two different approaches so far. The first, I've attached an .onSubmit to the TextField. When I hit enter or return, it works but it doesn't dismiss the Alert (even if I set $self.alertPresented to false.

The second, I've tried attaching a .keyboardShortcut(.return) to the OK Button itself but all this does is highlight the cancel Button for some reason (much in the same way I want to highlight the OK Button), and when I hit return / or enter, the Alert disappears like someone clicked the cancel Button.

So, just wondering if this is possible in the format I have above, where the Alert has a TextField and when it's all done in an .alert enclosure attached to a Button. Thank you.


Solution

  • You are looking for the .defaultAction keyboard shortcut.

    The standard keyboard shortcut for the default button, consisting of the Return (↩) key and no modifiers.

    On macOS, the default button is designated with special coloration. If more than one control is assigned this shortcut, only the first one is emphasized.

    .alert("Project Name:", isPresented: self.$alertPresented)
    {
        TextField("", text: self.$userInput)
        Button("OK") { print("OK Pressed!") }
            .disabled(userInput.isEmpty)
            .keyboardShortcut(.defaultAction)
        Button("Cancel", role: .cancel) { }
    }
    

    Note that you should put the Cancel button after the OK button. It seems like a button with role: .cancel is also implicitly a .defaultAction, so we need to put the OK button first in order to highlight it.