Key command for searchable modifier on macOS

Viewed 861

One of the new features introduced in iOS 15 SwiftUI 3.0 was the .searchable view modifier. Here is a simple example of how it works below. I would like to add the ability to search by pressing ⌘F as most apps have. How can I implement that functionality? As far as I am aware the .keyboardShortcut modifier can only be used on Button views which is quite limiting. Is there a way or workaround? Thanks! :)

struct ContentView: View {
    @State var searchText = ""
    private let fruits = ["apple", "banana", "plum", "grape"]
    
    var filteredFruits: [String] {
        if !searchText.isEmpty {
             return fruits.filter { $0.starts(with: searchText.lowercased()) }
        } else {
            return fruits
        }
    }

    var body: some View {
        NavigationView {
            List {
                ForEach(filteredFruits, id: \.self) { fruit in
                    Text(fruit.capitalized)
                }
            }
            .navigationBarTitle("Search")
            .searchable(text: $searchText) // Need to add key command to search (⌘F)
        }
    }
}
1 Answers

You can use SwiftUI-Introspect to get the underlying UISearchBar, and then create a hidden button triggered by the keyboard shortcut to focus the search bar.

The example below allows you to do ⌘F to activate the search bar.

Example:

struct ContentView: View {
    @State private var searchText = ""
    @State private var searchBar: UISearchBar?
    private let fruits = ["apple", "banana", "plum", "grape"]

    var filteredFruits: [String] {
        if !searchText.isEmpty {
             return fruits.filter { $0.starts(with: searchText.lowercased()) }
        } else {
            return fruits
        }
    }

    var body: some View {
        NavigationView {
            List {
                ForEach(filteredFruits, id: \.self) { fruit in
                    Text(fruit.capitalized)
                }
            }
            .navigationBarTitle("Search")
            .searchable(text: $searchText)
            .background(
                Button("Search fruits") {
                    focusSearchBar()
                }
                .keyboardShortcut("F", modifiers: .command)
                .hidden()
            )
        }
        .introspectNavigationController { nav in
            searchBar = nav.navigationBar.subviews.first { view in
                view is UISearchBar
            } as? UISearchBar
        }
    }

    private func focusSearchBar() {
        searchBar?.becomeFirstResponder()
    }
}

Result:

Result

Related