SwiftUI Design Tokens & Theming System (Production-Scale)

SwiftUI Design Tokens & Theming System (Production-Scale)

Source: Dev.to

๐Ÿง  What Are Design Tokens? ## ๐Ÿ“ฆ 1. Core Token Categories ## ๐Ÿ“ 2. Spacing Tokens ## ๐Ÿ”ฒ 3. Corner Radius Tokens ## ๐ŸŽจ 4. Color Tokens (Semantic, Not Visual) ## ๐Ÿ”ค 5. Typography Tokens ## ๐ŸงŠ 6. Elevation & Material Tokens ## ๐Ÿ•บ 7. Animation Tokens ## ๐ŸŒ— 8. Theme Container ## ๐Ÿ” 9. Supporting Multiple Themes ## ๐Ÿงช 10. Previews Become Powerful ## ๐Ÿš€ Final Thoughts As SwiftUI apps grow, UI consistency becomes fragile. The solution is design tokens โ€” a single source of truth for all visual decisions. This post shows how to build a production-grade design token & theming system in SwiftUI that scales cleanly. Design tokens are named, semantic values, not raw numbers. Tokens express intent, not implementation. A complete system usually includes: Weโ€™ll define each cleanly. Create a theme model: Inject via environment: Design validation becomes instant. A design token system gives you: Once you adopt tokens, you never go back. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK: .padding(12) .cornerRadius(16) .foregroundColor(.blue) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: .padding(12) .cornerRadius(16) .foregroundColor(.blue) CODE_BLOCK: .padding(12) .cornerRadius(16) .foregroundColor(.blue) CODE_BLOCK: .padding(.md) .cornerRadius(.card) .foregroundStyle(.accent) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: .padding(.md) .cornerRadius(.card) .foregroundStyle(.accent) CODE_BLOCK: .padding(.md) .cornerRadius(.card) .foregroundStyle(.accent) CODE_BLOCK: enum Spacing { static let xs: CGFloat = 4 static let sm: CGFloat = 8 static let md: CGFloat = 16 static let lg: CGFloat = 24 static let xl: CGFloat = 32 } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: enum Spacing { static let xs: CGFloat = 4 static let sm: CGFloat = 8 static let md: CGFloat = 16 static let lg: CGFloat = 24 static let xl: CGFloat = 32 } CODE_BLOCK: enum Spacing { static let xs: CGFloat = 4 static let sm: CGFloat = 8 static let md: CGFloat = 16 static let lg: CGFloat = 24 static let xl: CGFloat = 32 } CODE_BLOCK: .padding(Spacing.md) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: .padding(Spacing.md) CODE_BLOCK: .padding(Spacing.md) CODE_BLOCK: enum Radius { static let sm: CGFloat = 6 static let md: CGFloat = 12 static let lg: CGFloat = 20 static let card: CGFloat = 16 } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: enum Radius { static let sm: CGFloat = 6 static let md: CGFloat = 12 static let lg: CGFloat = 20 static let card: CGFloat = 16 } CODE_BLOCK: enum Radius { static let sm: CGFloat = 6 static let md: CGFloat = 12 static let lg: CGFloat = 20 static let card: CGFloat = 16 } CODE_BLOCK: Color.blue Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: enum AppColor { static let background = Color("Background") static let surface = Color("Surface") static let accent = Color("Accent") static let textPrimary = Color("TextPrimary") static let textSecondary = Color("TextSecondary") } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: enum AppColor { static let background = Color("Background") static let surface = Color("Surface") static let accent = Color("Accent") static let textPrimary = Color("TextPrimary") static let textSecondary = Color("TextSecondary") } CODE_BLOCK: enum AppColor { static let background = Color("Background") static let surface = Color("Surface") static let accent = Color("Accent") static let textPrimary = Color("TextPrimary") static let textSecondary = Color("TextSecondary") } CODE_BLOCK: enum AppFont { static let title = Font.system(size: 28, weight: .bold) static let headline = Font.system(size: 20, weight: .semibold) static let body = Font.system(size: 16) static let caption = Font.system(size: 13) } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: enum AppFont { static let title = Font.system(size: 28, weight: .bold) static let headline = Font.system(size: 20, weight: .semibold) static let body = Font.system(size: 16) static let caption = Font.system(size: 13) } CODE_BLOCK: enum AppFont { static let title = Font.system(size: 28, weight: .bold) static let headline = Font.system(size: 20, weight: .semibold) static let body = Font.system(size: 16) static let caption = Font.system(size: 13) } CODE_BLOCK: Text("Title") .font(AppFont.title) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: Text("Title") .font(AppFont.title) CODE_BLOCK: Text("Title") .font(AppFont.title) CODE_BLOCK: enum Elevation { static let card = CGFloat(4) static let modal = CGFloat(12) } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: enum Elevation { static let card = CGFloat(4) static let modal = CGFloat(12) } CODE_BLOCK: enum Elevation { static let card = CGFloat(4) static let modal = CGFloat(12) } CODE_BLOCK: .background(.ultraThinMaterial) .shadow(radius: Elevation.card) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: .background(.ultraThinMaterial) .shadow(radius: Elevation.card) CODE_BLOCK: .background(.ultraThinMaterial) .shadow(radius: Elevation.card) CODE_BLOCK: enum Motion { static let fast = Animation.easeOut(duration: 0.15) static let standard = Animation.easeInOut(duration: 0.25) static let slow = Animation.spring(response: 0.45) } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: enum Motion { static let fast = Animation.easeOut(duration: 0.15) static let standard = Animation.easeInOut(duration: 0.25) static let slow = Animation.spring(response: 0.45) } CODE_BLOCK: enum Motion { static let fast = Animation.easeOut(duration: 0.15) static let standard = Animation.easeInOut(duration: 0.25) static let slow = Animation.spring(response: 0.45) } CODE_BLOCK: struct AppTheme { let colors: Colors let spacing: Spacing.Type let radius: Radius.Type } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: struct AppTheme { let colors: Colors let spacing: Spacing.Type let radius: Radius.Type } CODE_BLOCK: struct AppTheme { let colors: Colors let spacing: Spacing.Type let radius: Radius.Type } CODE_BLOCK: .environment(\.theme, currentTheme) Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: .environment(\.theme, currentTheme) CODE_BLOCK: .environment(\.theme, currentTheme) CODE_BLOCK: enum ThemeKind { case light case dark case highContrast } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: enum ThemeKind { case light case dark case highContrast } CODE_BLOCK: enum ThemeKind { case light case dark case highContrast } CODE_BLOCK: #Preview("Dark") { ContentView() .environment(\.theme, .dark) } Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: #Preview("Dark") { ContentView() .environment(\.theme, .dark) } CODE_BLOCK: #Preview("Dark") { ContentView() .environment(\.theme, .dark) } - slightly different padding values - inconsistent corner radii - random colors hardcoded everywhere - dark mode bugs - accessibility issues - painful rebranding work - light/dark mode - accessibility contrast - brand changes - system appearance - accessibility - user preference - A/B testing - consistency - accessibility - faster iteration - safer refactors - easy rebranding - cleaner code - happier designers