Skip to content

Custom glass sidebar on iPad Workaround

As there is currently no Sidebar-like sheet on iPad, I'm using a NavigationStack in a View with .glassEffect applied:

Discussion: https://developer.apple.com/forums/thread/793627

This came with two issues that needed workarounds:

FB19252414: Container glass background disappears when a Menu with a glass effect appears

When .glassEffect() is used to build a custom sideways sheet-like presentation on iPad, the glass background disappears when a Menu with a glass effect appears.

(this can be worked around by putting the glass in .background using Color.clear.glassEffect() )

Toolbar buttons in the bottom toolbar align with the device safe area instead of the NavigationStack container / are shown without padding inside the container:

(this can be worked around by avoiding the toolbar and using a .safeAreaBar + custom standalone glass buttons)

Example code:

swift
// » SwiftUI Garden
// » https://swiftui-garden.com/Misc/iOS-26/Custom-glass-sidebar-on-iPad-Workaround

import MapKit
import SwiftUI

struct CustomGlassSidebarExample: View {

    var body: some View {
        Map()
            .overlay(alignment: .leading) {

                NavigationStack {
                    CustomGlassSidebarExampleScrollView()
                        .toolbar {
                            ToolbarItem(placement: .topBarTrailing) {
                                Menu(
                                    content: {
                                        Button("Example") {}
                                    },
                                    label: {
                                        Image(systemName: "ellipsis")
                                    }
                                )
                            }
                        }
                        .toolbar {
                            ToolbarItemGroup(placement: .bottomBar) {
                                Button("Example", systemImage: "square.dashed") {}

                                Spacer()

                                Button("Example", systemImage: "square.dashed") {}
                            }

                        }
                        .navigationTitle("Example")
                        .navigationBarTitleDisplayMode(.inline)
                        .containerBackground(Color.clear, for: .navigation)
                }
                .frame(width: 400)
                .frame(maxHeight: .infinity)
                // .background + Color.clear is a workaround for glass disappearing when a Menu opens (last tested on Beta 8)
                .background {
                    Color.clear
                        .glassEffect(in: .rect(cornerRadius: 36))
                }
                .clipShape(.rect(cornerRadius: 36))
                .padding([.horizontal, .top])
            }
    }

}

struct CustomGlassSidebarExampleScrollView: View {

    var body: some View {

        ScrollView {
            VStack {
                ForEach(1 ... 30, id: \.self) { i in
                    NavigationLink(
                        destination: {
                            CustomGlassSidebarExampleScrollView()
                        },
                        label: {
                            RoundedRectangle(cornerRadius: 12)
                                .fill(.background)
                                .frame(maxWidth: .infinity)
                                .frame(height: 100)
                                .overlay {
                                    Text("\(i)")
                                }
                        }
                    )
                }
            }
            .padding()
        }
        .navigationTitle("Glass Sidebar Example")
        .navigationBarTitleDisplayMode(.inline)
        .containerBackground(Color.clear, for: .navigation)

    }
}

#Preview {
    CustomGlassSidebarExample()
}