Swift SettingsKit
Status: Production Ready ✅ Last Updated: 2025-11-23 Dependencies: None (standalone Swift package) Latest Version: SettingsKit 1.0.0+
Supported Toolchains
Minimum Requirements:
- Swift: 6.0+ (required for @Observable macro and SettingsKit compilation)
- Xcode: 16.0+ (provides Swift 6.0 toolchain)
- Platforms: iOS 17.0+ / macOS 14.0+ / watchOS 10.0+ / tvOS 17.0+ / visionOS 1.0+
Note: While @Observable was introduced in Swift 5.9, SettingsKit's Package.swift specifies Swift 6.0+ as the minimum toolchain version. All examples in this skill target Swift 6.0+.
Quick Start (5 Minutes)
1. Add SettingsKit Package
Add the Swift package to your project via Xcode:
// File → Add Package Dependencies
// Enter: https://github.com/aeastr/SettingsKit.git
// Version: 1.0.0 or later
Or via Package.swift:
dependencies: [
.package(url: "https://github.com/aeastr/SettingsKit.git", from: "1.0.0")
]
Why this matters:
- SettingsKit requires iOS 17+ / macOS 14+ for modern SwiftUI features
- Swift 6.0+ is required for @Observable macro support
- Framework is platform-adaptive across all Apple platforms
2. Create Observable Settings Model
import SwiftUI
import SettingsKit
@Observable
class AppSettings {
var notificationsEnabled = true
var darkMode = false
var username = "Guest"
var fontSize: Double = 14.0
}
CRITICAL:
- Use
@Observablemacro (not@PublishedorObservableObject) - SettingsKit is designed for Swift's modern observation system
- Settings model must be in SwiftUI environment for binding
3. Implement SettingsContainer Protocol
struct MySettings: SettingsContainer {
@Environment(AppSettings.self) var appSettings
var settingsBody: some SettingsContent {
@Bindable var settings = appSettings
SettingsGroup("General", systemImage: "gear") {
SettingsItem("Notifications") {
Toggle("Enable", isOn: $settings.notificationsEnabled)
}
SettingsItem("Dark Mode") {
Toggle("Enable", isOn: $settings.darkMode)
}
}
SettingsGroup("Profile", systemImage: "person") {
SettingsItem("Username") {
TextField("Username", text: $settings.username)
}
SettingsItem("Font Size") {
Slider(value: $settings.fontSize, in: 10...24)
Text("\(Int(settings.fontSize))pt")
}
}
}
}
CRITICAL:
- Must use
@Bindablewrapper to create bindings from @Observable model settingsBodyreturnsSettingsContent(notView)- Groups appear as navigation links in sidebar style (tappable rows)
4. Add to Your App
import SwiftUI
import SettingsKit
@main
struct MyApp: App {
@State private var settings = AppSettings()
var body: some Scene {
WindowGroup {
MySettings()
.environment(settings)
}
}
}
Result: Complete settings interface with:
- Automatic navigation (sidebar on iPad/Mac, single column on iPhone)
- Built-in search functionality
- Platform-adaptive presentation
- Reactive state updates
The 4-Step Setup Process
Step 1: Install Package Dependency
Add SettingsKit via Swift Package Manager in Xcode:
- File → Add Package Dependencies
- Enter repository URL:
https://github.com/aeastr/SettingsKit.git - Select "Up to Next Major Version" from "1.0.0"
- Add to your app target
Key Points:
- Requires Xcode 16.0+ for Swift 6.0 support
- Package includes all platforms (iOS, macOS, watchOS, tvOS, visionOS)
- No additional configuration needed
Step 2: Define Settings Data Model
Create an @Observable class to hold your settings state:
import SwiftUI
@Observable
class AppSettings {
// General settings
var notificationsEnabled = true
var soundEnabled = true
var hapticFeedback = true
// Appearance settings
var darkMode = false
var accentColor: Color = .blue
var fontSize: Double = 16.0
// User profile
var username = ""
var email = ""
var profileImageURL: URL?
}
Key Points:
- Use
@Observablemacro (Swift 6.0+) for modern observation - Initialize all properties with default values
- Keep settings model separate from view logic
- Can include computed properties for derived state
Step 3: Build Settings Hierarchy
Implement SettingsContainer protocol to define your settings UI:
import SettingsKit
struct MySettings: SettingsContainer {
@Environment(AppSettings.self) var appSettings
var settingsBody: some SettingsContent {
@Bindable var settings = appSettings
// Navigation group (tappable row)
SettingsGroup("General", systemImage: "gear") {
SettingsItem("Notifications") {
Toggle("Enable", isOn: $settings.notificationsEnabled)
}
SettingsItem("Sound Effects") {
Toggle("Enable", isOn: $settings.soundEnabled)
}
}
.settingsTags(["notifications", "sounds", "alerts"])
// Inline group (section header)
SettingsGroup("Quick Settings", .inline) {
SettingsItem("Dark Mode") {
Toggle("Enable", isOn: $settings.darkMode)
}
}
// Nested navigation
SettingsGroup("Profile", systemImage: "person") {
SettingsGroup("Account", systemImage: "person.circle") {
SettingsItem("Username") {
TextField("Username", text: $settings.username)
}
SettingsItem("Email") {
TextField("Email", text: $settings.email)
}
}
}
}
}
Key Points:
SettingsGroupcreates navigation links (default) or section headers (.inline)SettingsItemwraps individual controls- Add
.settingsTags([...])for enhanced search discoverability - Groups can be nested infinitely for deep hierarchies
Step 4: Configure Presentation Style
Choose how settings are displayed:
// Sidebar style (default) - Split view on iPad/Mac
MySettings(settings: settings)
.settingsStyle(.sidebar)
// Single column style - Clean list on all platforms
MySettings(settings: settings)
.settingsStyle(.single)
// Custom style - Full control over appearance
MySettings(settings: settings)
.settingsStyle(MyCustomStyle())
Key Points:
.sidebar: NavigationSplitView with selection-based navigation (default).single: Single NavigationStack with push navigation- Custom styles conform to
SettingsStyleprotocol - Platform automatically adapts to device context
Critical Rules
Always Do
✅ Use @Observable for settings models - Required for SettingsKit's reactive system ✅ Wrap environment settings with @Bindable - Enables two-way binding in settingsBody ✅ Add searchable tags to important groups - Improves discoverability via .settingsTags([...]) ✅ Keep settings models in SwiftUI environment - Use .environment(settings) on parent view ✅ Use SettingsItem for all interactive controls - Ensures proper search indexing
Never Do
❌ Never use ObservableObject with @Published - SettingsKit requires modern @Observable ❌ Never create bindings without @Bindable wrapper - Will cause compilation errors ❌ Never put heavy computation in settingsBody - Computed on every render, keep lightweight ❌ Never forget to inject settings into environment - Causes runtime crashes ❌ Never use CustomSettingsGroup for simple controls - Bypasses search indexing unnecessarily
Known Issues Prevention
This skill prevents 5 documented issues:
Issue #1: "Cannot convert value of type 'Binding<T>' to expected argument type 'Binding<U>'"
Error: Compilation error when trying to bi