How to use the new inspector SwiftUI view modifier

Making a secondary column has never been simpler with iOS 17+

Thomas Ricouard
3 min readSep 21, 2023

The latest version of SwiftUI introduced an interesting new modifier, .inspector.

On iPad and macOS, you can now easily open an inspector with full opening/closing animation. What is an inspector? Well, think about Xcode, how you can close and open the panel on the side.

Here is how it behaves:

inspector on an iOS 17 landscape iPad
inspector on an iOS 17 portrait iPad

It’s also behaving the same on macOS, switching between a column and an overlapping inspector as you resize the window.

It’s a great addition to SwiftUI. On Ice Cubes for macOS / iPadOS, I used to draw my secondary column myself with an HStack and a Divider. It makes it super easy to provide a secondary column to your apps.

Here is my previous code:

@main
struct IceCubesApp: App {
var body: some Scene {
WindowGroup {
appView
}
}

@ViewBuilder
private var appView: some View {
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
sidebarView
} else {
tabBarView
}
}

private var sidebarView: some View {
SideBarView(selectedTab: $selectedTab,
popToRootTab: $popToRootTab,
tabs: availableTabs)
{
HStack(spacing: 0) {
/ ... tab content .../
if userPreferences.showiPadSecondaryColumn {
Divider().edgesIgnoringSafeArea(.all)
notificationsSecondaryColumn
}
}
}

private var notificationsSecondaryColumn: some View {
NotificationsTab(popToRootTab: $popToRootTab, lockedType: nil)
.environment(\.isSecondaryColumn, true)
}
}

Here is my new code:

@main
struct IceCubesApp: App {
var body: some Scene {
WindowGroup {
appView
}
}

@ViewBuilder
private var appView: some View {
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac {
sidebarView
} else {
tabBarView
}
}

private var sidebarView: some View {
SideBarView(selectedTab: $selectedTab,
popToRootTab: $popToRootTab,
tabs: availableTabs)
{
/ ... tab content .../
}
.inspector(isPresented: $userPreferences.showiPadSecondaryColumn) {
notificationsSecondaryColumn
}
}

private var notificationsSecondaryColumn: some View {
NotificationsTab(popToRootTab: $popToRootTab, lockedType: nil)
.environment(\.isSecondaryColumn, true)
.inspectorColumnWidth(.secondaryColumnWidth)
}
}

You can give width to your column using .inspectorColumnWidth. In my case, it’s fixed, but you could even provide a more fine-tuned width using the min, max and ideal width parameters.

You’re still responsible for providing the button to open it and close it yourself.

struct NotificationsTab: View {
@Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool

var body: some View {
NavigationStack {
NotificationsListView()(
.toolbar {
if UIDevice.current.userInterfaceIdiom == .pad {
if (!isSecondaryColumn && !userPreferences.showiPadSecondaryColumn) || isSecondaryColumn {
SecondaryColumnToolbarItem()
}
}
}
.toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar)
}
}
}

public struct SecondaryColumnToolbarItem: ToolbarContent {
@Environment(\.isSecondaryColumn) private var isSecondaryColumn
@Environment(UserPreferences.self) private var preferences

public init() {}

public var body: some ToolbarContent {
ToolbarItem(placement: isSecondaryColumn ? .navigationBarLeading : .navigationBarTrailing) {
Button {
withAnimation {
preferences.showiPadSecondaryColumn.toggle()
}
} label: {
Image(systemName: "sidebar.right")
}
}
}
}

SF Symbols have a lot of icons to match your sidebar content and side. I’m using sidebar.right in my case.

SF Symbols sidebar icons

You can browse the full code source of Ice Cubes on Github

And download it on the App Store

And that’s it; you can now add an inspector to your SwiftUI apps! 🚀

--

--

Thomas Ricouard

📱 🚀 🇫🇷 [Entrepreneur, iOS/Mac & Web dev] | Now @Medium, @Glose 📖| Past @google 🔍 | Co-founded few companies before, a movies 🎥 app and smart browser one.