NavigationSplitView hide sidebar toggle button

I'm trying to implement the same UI used by the Settings app on iPad: a split view with two columns that are visible at all times.

This code produces the layout i want, but I would like to hide the "toggle sidebar visibility" button that the system introduces.

Is there a SwiftUI API I can use to hide this button? Maybe an alternate way to setup views that tells the system that the button is not necessary?

struct SomeView: View {
  var body: some View {
    NavigationSplitView(
      columnVisibility: .constant(.all),
      sidebar: { Text("sidebar") },
      detail: { Text("detail") }
    )
    .navigationSplitViewStyle(.balanced)
  }
}

You can use the toolbar(_:for:) modifier on your sidebar view like this: .toolbar(.hidden, for: .navigationBar). You can find details in the documentation here.

Here's the resulting view:

struct SomeView: View {
  var body: some View {
    NavigationSplitView(
      columnVisibility: .constant(.all),
      sidebar: { 
          Text("sidebar")
               .toolbar(.hidden, for: .navigationBar)
      },
      detail: { Text("detail") }
    )
    .navigationSplitViewStyle(.balanced)
  }
}

The first argument sets the visibility, and the second arguments specifies which bar to hide (which in your case is .navigationBar).

I'm a newbie in SwiftUI development, but I had the same question for my macOS application.

The answer I've found seems a little bit ugly, but using SwiftUI-Introspect library you can just remove corresponding toolbar item. Maybe it will be helpful for someone.

        .introspect(.window, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { nsWindow in
            if let toolbar = nsWindow.toolbar {
                if let index = toolbar.items.firstIndex(where: { $0.itemIdentifier.rawValue == "com.apple.SwiftUI.navigationSplitView.toggleSidebar" }) {
                    toolbar.removeItem(at: index)
                }
            }
        }

.toolbar(removing: .sidebarToggle) ?

Quoting Apple: "On some platforms, NavigationSplitView adds a sidebarToggle toolbar item. Use the toolbar(removing:) modifier to remove the default item."

More on that her: https://developer.apple.com/documentation/swiftui/view/toolbar(removing:)

(Requires iOS 17.0+ / macOS 14.0+)

Although Apple introduced .toolbar(removing: .sidebarToggle) finally, users can still drag the divider to change the column width and hide the side bar on macOS, and since sidebar toggle button is removed, users could never get back. In Sonoma Xcode15, developers have to use something like this:

        .introspect(.navigationSplitView, on: .macOS(.v13,.v14,.v15)) { splitview in
            if let delegate = splitview.delegate as? NSSplitViewController {
                delegate.splitViewItems.first?.canCollapse = false
            }
        }

But it fails to work on Sequoia with Xcode16. Developers have to search around again to make it work just like the built-in Settings App, it's a shame.

I found out that using canCollapseFromWindowResize with canCollapse did the trick and you cannot hide the sidebar anymore by dragging it on macOS.

        .introspect(.navigationSplitView, on: .macOS(.v13,.v14,.v15)) { splitview in
            if let delegate = splitview.delegate as? NSSplitViewController {
                delegate.splitViewItems.first?.canCollapse = false
                delegate.splitViewItems.first?.canCollapseFromWindowResize = false
            }
        }

But I agree it's a shame that options/features that they are clearly using in many of their apps are somehow still not available in SwiftUI. All the thanks to swiftui-introspect developers for making possible to overcome Apple's dumb mistakes.

NavigationSplitView hide sidebar toggle button
 
 
Q