Lightweight, beautiful toast notifications for SwiftUI — no UIKit required.
ToastKit lets you show brief notification banners (toasts) anywhere in your SwiftUI app with a single line of code. No UIKit, no view controllers, no window hacks — just pure SwiftUI.
ToastManager.shared.show(.success("Profile saved!"))
ToastManager.shared.show(.error("Something went wrong"))
ToastManager.shared.show(.warning("Session expiring soon"))In Xcode go to File → Add Package Dependencies and paste:
https://github.com/codewithswiftly/ToastKit.git
Or in Package.swift:
.package(url: "https://github.com/codewithswiftly/ToastKit.git", from: "1.0.0")Add .toastContainer() once to your root view. That's it.
// In your App file
import SwiftUI
import ToastKit
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.toastContainer() // ← add this once
}
}
}import ToastKit
// In a ViewModel, button action, async task — anywhere
ToastManager.shared.show(.success("Saved!"))
ToastManager.shared.show(.error("Could not connect"))
ToastManager.shared.show(.warning("Low storage"))
ToastManager.shared.show(.info("New version available"))
ToastManager.shared.show(.plain("Copied to clipboard"))struct ProfileView: View {
@State private var toast: Toast? = nil
var body: some View {
Button("Save Profile") {
toast = .success("Profile updated!")
}
.toast($toast) // ← binds the state to ToastKit
}
}// Custom icon (SF Symbol), color, duration, and position
let toast = Toast(
message: "Achievement unlocked!",
style: .custom(icon: "star.fill", color: .purple),
duration: 5,
position: .bottom
)
ToastManager.shared.show(toast)// Dismiss the current toast immediately
ToastManager.shared.dismiss()
// Toasts can also be dismissed by tapping them| Style | Icon | Color | Use for |
|---|---|---|---|
.success |
✅ checkmark | Green | Completed actions |
.error |
❌ xmark | Red | Failures, errors |
.warning |
Orange | Cautions | |
.info |
ℹ️ info | Blue | Neutral messages |
.plain |
🔔 bell | Grey | Simple status |
.custom(icon:color:) |
Any SF Symbol | Any Color | Your own style |
// Show at the top (default)
ToastManager.shared.show(.success("Done!", position: .top))
// Show at the bottom
ToastManager.shared.show(.info("Syncing...", position: .bottom))If you call .show() multiple times rapidly, ToastKit queues them and shows them one at a time. You never get two toasts overlapping.
// These will show in order, one after the other
ToastManager.shared.show(.success("Step 1 complete"))
ToastManager.shared.show(.info("Step 2 starting"))
ToastManager.shared.show(.success("All done!"))struct SettingsView: View {
@State private var username = ""
var body: some View {
Form {
TextField("Username", text: $username)
Button("Save Changes") {
Task { await saveChanges() }
}
Button("Delete Account", role: .destructive) {
ToastManager.shared.show(
Toast(
message: "Account deleted. Sorry to see you go.",
style: .error,
duration: 5,
position: .bottom
)
)
}
}
}
func saveChanges() async {
do {
try await API.updateProfile(username: username)
ToastManager.shared.show(.success("Username updated!"))
} catch {
ToastManager.shared.show(.error("Failed to save. Try again."))
}
}
}ToastKit/
├── Sources/ToastKit/
│ ├── Toast.swift # The Toast model + convenience factories
│ ├── ToastManager.swift # Observable manager — show, dismiss, queue
│ ├── ToastView.swift # The SwiftUI view that renders a toast
│ ├── ToastContainerModifier.swift # .toastContainer() — attach to root view
│ └── ToastModifier.swift # .toast($binding) — SwiftUI binding style
└── Tests/ToastKitTests/
└── ToastKitTests.swift
- iOS 16+
- Swift 5.9+
- Xcode 15+
- Zero dependencies — pure SwiftUI
MIT © 2026 Rahul Das Gupta
If you found this project useful, consider giving it a ⭐️ on GitHub!