A modern, type-safe router for SwiftUI with a clean declarative API
Add SnazzyRouter to your project through Xcode:
- File β Add Package Dependencies...
- Enter the package URL:
https://github.com/DubonYaar/SnazzyRouter.git - Click Add Package
Or add it to your Package.swift:
dependencies: [
.package(url: "https://github.com/DubonYaar/SnazzyRouter.git", from: "1.0.1")
]import SnazzyRouter
import SwiftUI
enum AppRoute: Routable {
case home
case profile(userId: String)
case settings
case detail(item: String)
@ViewBuilder
var view: some View {
switch self {
case .home:
HomeView()
case .profile(let userId):
ProfileView(userId: userId)
case .settings:
SettingsView()
case .detail(let item):
DetailView(item: item)
}
}
}import SnazzyRouter
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
Router(AppRoute.self) { router in
VStack {
Text("Welcome to SnazzyRouter!")
.font(.largeTitle)
Button("Go to Profile") {
router.push(.profile(userId: "123"))
}
}
.padding()
}
}
}
}import SnazzyRouter
import SwiftUI
struct ProfileView: View {
let userId: String
@Environment(RouterState<AppRoute>.self) var router
var body: some View {
VStack {
Text("Profile: \(userId)")
Button("Go to Settings") {
router.push(.settings)
}
Button("Back") {
router.pop()
}
Button("Back to Home") {
router.popToRoot()
}
}
}
}SnazzyRouter supports all SwiftUI modal types:
import SnazzyRouter
import SwiftUI
struct HomeView: View {
@Environment(RouterState<AppRoute>.self) var router
var body: some View {
VStack(spacing: 20) {
// Sheet
Button("Show Settings Sheet") {
router.sheet = RouterModalItem(
destination: .settings,
dismiss: {
print("Settings dismissed")
}
)
}
// Full Screen Cover
Button("Show Full Screen") {
router.fullScreenCover = RouterModalItem(
destination: .detail(item: "Important")
)
}
// Popover (iPad)
Button("Show Popover") {
router.popover = RouterModalItem(
destination: .profile(userId: "popover")
)
}
}
}
}Built-in support for alerts and confirmation dialogs:
import SnazzyRouter
import SwiftUI
struct SettingsView: View {
@Environment(RouterState<AppRoute>.self) var router
var body: some View {
VStack(spacing: 20) {
// Simple Alert
Button("Show Alert") {
router.showAlert(
Alert(
title: Text("Hello!"),
message: Text("This is a snazzy alert"),
dismissButton: .default(Text("OK"))
)
)
}
// Confirmation Dialog
Button("Show Options") {
router.showConfirmationDialog(
title: "Choose an Action",
message: "What would you like to do?",
actions: [
DialogAction(title: "Edit") {
router.push(.profile(userId: "edit"))
},
DialogAction(title: "Delete", role: .destructive) {
print("Delete tapped")
},
DialogAction(title: "Cancel", role: .cancel) {
print("Cancelled")
}
]
)
}
}
}
}Access the router state directly for complex navigation logic:
import SnazzyRouter
import SwiftUI
struct DeepLinkHandler: View {
@Environment(RouterState<AppRoute>.self) private var router
var body: some View {
Color.clear
.onOpenURL { url in
handleDeepLink(url: url)
}
}
private func handleDeepLink(url: URL) {
// Parse URL and navigate
router.popToRoot()
router.push(.profile(userId: "deep-link-user"))
}
}You can create and manage your own router state:
import SnazzyRouter
import SwiftUI
@State private var routerState = RouterState<AppRoute>()
var body: some View {
Router(AppRoute.self, provider: routerState) { router in
// Your content
}
}Routable- Protocol for defining navigable destinations (requiresHashable,Identifiable,Equatable)RouterState<D>- Observable state container for navigationRouter<D, Content>- Main view component for routingRouterModalItem<D>- Modal presentation configurationDialogAction- Action for confirmation dialogsPopToMatch- Enum for specifying first or last occurrence (.first,.last)
push(_:)- Navigate to a destinationpop()- Go back one levelpopToRoot()- Return to root viewpopTo(_:match:)- Pop to a specific destination in the stackshowAlert(_:)- Display an alertshowConfirmationDialog(title:message:actions:)- Show confirmation dialog
Use popTo(_:match:) to navigate back to a specific route in the navigation stack:
@Environment(RouterState<AppRoute>.self) var router
// Pop to the last occurrence of .settings (default)
router.popTo(.settings)
// Pop to the first occurrence of .settings
router.popTo(.settings, match: .first)The match parameter accepts:
.last(default) - Pops to the most recent occurrence of the destination.first- Pops to the earliest occurrence of the destination
If the destination is not found in the navigation stack, no action is taken.
You can directly access and manipulate the navigation path:
@Environment(RouterState<AppRoute>.self) var router
// Read the current navigation path
let currentPath = router.path
// Get the count of destinations in the stack
let stackDepth = router.path.count
// Check if a specific route is in the path
let hasSettings = router.path.contains(.settings)
// Manually set the entire path
router.path = [.home, .profile(userId: "123"), .settings]
// Remove specific items from the path
router.path.removeAll { $0 == .settings }Contributions are welcome! Please feel free to submit a Pull Request.
SnazzyRouter is available under the MIT license. See the LICENSE file for more info.
Built with β€οΈ using SwiftUI and the power of snazziness.
Make your navigation snazzy!