Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI list multiselect with NavigationLink

In SwiftUI running on macOS, for a list of items where each item in the list is a NavigationLink, multi-selection does not work. If the exact same view does not include the NavigationLink it works fine. How can I have both multi-selection and NavigationLink in the same list running on macOS? Perhaps this requires a different method of constructing NavigationLinks that isn't tied to the list? Is that even possible? I've tried conditionally disabling the NavigationLink when multiple rows are selected, but this has no effect (e.g. .disabled(selection.count > 1)).

Example where multi-select does not work (notice in the screenshot when three results are shift-clicked the full selection shows up briefly and then snaps to the last clicked item):

struct TestListView: View {
  @State var selection = Set<String>()
  let options = ["a", "b", "c"]

  var body: some View {
    NavigationView {
      List(options, id: \.self, selection: $selection) { item in
        NavigationLink {
          Text(String(describing: selection))
        } label: {
          Text(item)
        }
      }
    }
  }
}

Screencast of the above code

Example where multi-select works fine:

struct TestListView: View {
  @State var selection = Set<String>()
  let options = ["a", "b", "c"]

  var body: some View {
    NavigationView {
      List(options, id: \.self, selection: $selection) { item in
        Text(item)
      }
      Text(String(describing: selection))
    }
  }
}

enter image description here

like image 713
Ethan Kay Avatar asked Dec 28 '25 21:12

Ethan Kay


1 Answers

Looks like I more or less had it in one of the question examples. A separate bug in a more complex example misled me. Solution is effectively the second option above.

In other words, don't try to mix NavigationLink and multi-selection. Instead skip the NavigationLink and put the destination view next to the List (only tested on macOS).

struct TestListView: View {
  @State var selection = Set<String>()
  let options = ["a", "b", "c"]

  var body: some View {
    NavigationView {
      List(options, id: \.self, selection: $selection) { item in
        Text(item)
      }
      if selection.isEmpty {
        Text("Empty")
      } else if selection.count > 1 {
        Text("Multiple")
      } else if let selection = selection.first {
        Text(selection)
      }
    }
  }
}
like image 112
Ethan Kay Avatar answered Dec 30 '25 16:12

Ethan Kay



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!