Skip to content

Instantly share code, notes, and snippets.

@ezefranca
Last active December 30, 2025 22:55
Show Gist options
  • Select an option

  • Save ezefranca/0c807415b3d152500c7e5f012897979b to your computer and use it in GitHub Desktop.

Select an option

Save ezefranca/0c807415b3d152500c7e5f012897979b to your computer and use it in GitHub Desktop.
An adaptive modifier that seamlessly toggles between a modal Sheet on compact layouts (iPhone) and a Navigation Push on regular layouts (iPad), maintaining a native Apple user experience.
import SwiftUI
struct SheetOrNavigateItemModifier<Item: Identifiable & Hashable, Destination: View>: ViewModifier {
@Binding var item: Item?
@ViewBuilder let destination: (Item) -> Destination
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
private var isRegular: Bool { horizontalSizeClass == .regular }
func body(content: Content) -> some View {
content
// Regular: push using item-driven navigation
.navigationDestination(item: navigationItemBinding) { value in
destination(value)
}
// Compact: present as sheet
.sheet(item: sheetItemBinding) { value in
NavigationStack {
destination(value)
}
}
// Optional: prevent mode-switch weirdness when size class changes mid-presentation
.onChange(of: horizontalSizeClass) { _, _ in
// If you want to be strict, uncomment:
// if item != nil { item = nil }
}
}
private var sheetItemBinding: Binding<Item?> {
Binding(
get: { isRegular ? nil : item },
set: { newValue in
guard !isRegular else { return }
item = newValue
}
)
}
private var navigationItemBinding: Binding<Item?> {
Binding(
get: { isRegular ? item : nil },
set: { newValue in
guard isRegular else { return }
item = newValue
}
)
}
}
extension View {
func sheetOrNavigate<Item: Identifiable & Hashable, Destination: View>(
item: Binding<Item?>,
@ViewBuilder destination: @escaping (Item) -> Destination
) -> some View {
modifier(SheetOrNavigateItemModifier(item: item, destination: destination))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment