Apple's desire to create a more cohesive experience across their platforms was clear this year at WWDC, SwiftUI is quickly positioning itself to take the wheel and drive multi-platform apps in the future.

The updated side bar behaviour and collapsable list is one step Apple has taken to move this incentive forward, with tailored experiences on iOS, iPadOS and MacOS all within the same control.

I built a sample app that demonstrates this behaviour in more detail, you can  download it here.


struct ListItem: Identifiable {
    var id = UUID()
    let name: String
    let iconName: String?
    let children: [ListItem]?
    
    init(name: String, iconName: String? = nil, children: [ListItem]? = nil) {
        self.name = name
        self.iconName = iconName
        self.children = children
    }
}

Here's a basic struct called ListItem which defines some parameters typical of a menu row, we're going to use this to generate the menu.

Next we'll quickly define the structure of our menu and submenus in an array.

let listItems: [ListItem] = [
    ListItem(name: "Email", iconName: "envelope", children: [
        ListItem(name: "Sub menu 1"),
        ListItem(name: "Sub menu 2"),
        ListItem(name: "Sub menu 3")
    ]),
    ListItem(name: "Calendar", iconName: "calendar"),
    ListItem(name: "Messages", iconName: "message", children: [
        ListItem(name: "Sub menu 4"),
        ListItem(name: "Sub menu 5"),
    ]),
]

We have three entries here; email has an icon and three children, Calendar has an icon and no children, messages has an icon and two children. Lastly we need to place these in a list and tell SwiftUI where to find our submenus.

var body: some View {
    List(listItems, children: \.children) { listItem in
        HStack {
            Image(systemName: listItem.iconName ?? "")
            Text(listItem.name)
        }
    }
}

Nice the children parameter in the constructor, this is a key path that tells swift where to find our children in the model, in this case it's our children variable so we pass in the  \.children key path.

And we have our collapsable list! To get the adaptable sidebar apple showed us at WWDC this year, wrap the above List in a NavigationView like so.

var body: some View {
    NavigationView {
        List(listItems, children: \.children) { listItem in
            HStack {
                Image(systemName: listItem.iconName ?? "")
                Text(listItem.name)
            }
        }
        .navigationTitle("Collapsable List")
    }
}

We can optionally add .listStyle(SidebarListStyle()) as a view modifier on List to make use of the new sidebar styling apple provides with iOS14, i've excluded it as i'm seeing inconsistent results in the current beta.

It really is that simple with SwitUI to build a sidebar with collapsable menus that adapts to multiple platforms, supports dark mode and makes use of SFSymbols.

Thanks for reading ✌️