Better Programming

Advice for programmers.

Follow publication

Using Sidebar in SwiftUI Without a NavigationView

Get to know SwiftUI’s new sidebar

Mohammed Imthathullah
Better Programming
Published in
4 min readNov 9, 2020
Apple music app screen with a sidebar
Apple showcasing the sidebar in its music app

SwiftUI is really easy and fast for prototyping UI. This opinion has been expressed by many developers in different wordings.

But how does SwiftUI fare against the complex requirements of a real-world project? At present, it has been in production for only just over a year, and we can’t find many SwiftUI apps in the App Store.

But if there is any good time to build and ship SwiftUI apps, it is right now.

Disclaimer: Your app’s minimum target needs to be iOS 13.

Even though most of the SwiftUI features which make it production-ready have shipped only with iOS 14, you can build a decent app for iOS 13 which becomes exceptional when the user updates.

Take the common requirement of a collection view in many apps. You can use the new lazy grids for iOS 14 and drop down to a combination of VStack and HStack as Paul explains in this article for iOS 13. Also, if your requirement can just be fulfilled using a list, then go for it in iOS 13.

But if your requirements are complex or you want to tweak the default behavior a little bit, you might find it difficult. Today we’ll tackle one such scenario where I want some tweaks to the default behavior. Over the coming weeks, we’ll see many more.

SidebarListStyle was introduced this year, and makes it so easy to get the default sidebar behavior in your app.

Just with those few lines, you get the default behavior of the sidebar in a nice master detail layout.

diagram showing layout of sidebar items to the left of the detail view portion of the screen
A sidebar with default behavior

You get a lot of things out of the box: a sidebar with spaced out list items, no separators, a nice indication for the selection, and a button to toggle the visibility of the sidebar. If you use the new Label for the list item, the images will be in the accentColor. So cool, with just a few lines of code! Now my requirement is to have the sidebar and the detail view, but I don't want them to be inside a NavigationView. Sounds simple, right? Let’s try.

Using HStack for a SplitView

And the output is…

screen with sidebar selections but no items in the detail view

Not what I expected to see from the above code. But SwiftUI views react to the environment; you can say that SwiftUI views are dependent on the environment. We got the spaced-out list items without a separator but no selection and hence no highlighting when tapped, and we need to frame the views in the required size.

I have no clue why removing the NavigationLink stops the List selection from working. You can get it to work by adding an onTapGesture to the Text. The selection parameter in the list in no longer required. You can fix the sidebar width by using the frame modifier.

Let’s try our luck this time.

screen showing sidebar items with the message “nothing is selected”

Again, this is not what I expected, but SwiftUI did its job perfectly. We can fix this easily by adding a Spacer() before and after detailView.

The functionality is working properly, so you can tap any item to select it. But there is no visual indication of which item is currently selected. To highlight the selection, add a background with accentColor.

Here’s the final output.

screen showing sidebar items, with item 2 highlighted, and the message “2 is selected”
The Desired Result

And here’s the code to get that output.

We’ve used an HStack and a contentShape modifier so that tapping anywhere on the list item enables selection.

This is not the perfect solution, but this works. It took me some mental preparation to share working solutions publicly rather than waiting for the perfect solution all the time.

Happy coding!

Mohammed Imthathullah
Mohammed Imthathullah

Written by Mohammed Imthathullah

Aspiring Author. Mostly writes code and sometimes articles.

Responses (1)

Write a response