As SwiftUI apps grow, UI consistency becomes fragile.
You start seeing:
- slightly different padding values
- inconsistent corner radii
- random colors hardcoded everywhere
- dark mode bugs
- accessibility issues
- painful rebranding work
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.
π§ What Are Design Tokens?
Design tokens are named, semantic values, not raw numbers.
Bad:
.padding(12)
.cornerRadius(16)
.foregroundColor(.blue)
Good:
.padding(.md)
.cornerRadius(.card)
.foregroundStyle(.accent)
Tokens express intent, not implementation.
π¦ 1. Core Token Categories
A complete system usually includes:
- Spacing
- Radius
- Typography
- Colors
- Elevation
- Animation
- Opacity
Weβll define each cleanly.
π 2. Spacing Tokens
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
}
Usage:
.padding(Spacing.md)
π² 3. Corner Radius Tokens
enum Radius {
static let sm: CGFloat = 6
static let md: CGFloat = 12
static let lg: CGFloat = 20
static let card: CGFloat = 16
}
π¨ 4. Color Tokens (Semantic, Not Visual)
Never do:
Color.blue
Instead:
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")
}
Assets handle:
- light/dark mode
- accessibility contrast
- brand changes
π€ 5. Typography Tokens
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)
}
Usage:
Text("Title")
.font(AppFont.title)
π§ 6. Elevation & Material Tokens
enum Elevation {
static let card = CGFloat(4)
static let modal = CGFloat(12)
}
.background(.ultraThinMaterial)
.shadow(radius: Elevation.card)
πΊ 7. Animation Tokens
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)
}
π 8. Theme Container
Create a theme model:
struct AppTheme {
let colors: Colors
let spacing: Spacing.Type
let radius: Radius.Type
}
Inject via environment:
.environment(\.theme, currentTheme)
π 9. Supporting Multiple Themes
enum ThemeKind {
case light
case dark
case highContrast
}
Switch dynamically:
- system appearance
- accessibility
- user preference
- A/B testing
π§ͺ 10. Previews Become Powerful
#Preview("Dark") {
ContentView()
.environment(\.theme, .dark)
}
Design validation becomes instant.
π Final Thoughts
A design token system gives you:
- consistency
- accessibility
- faster iteration
- safer refactors
- easy rebranding
- cleaner code
- happier designers
Once you adopt tokens, you never go back.
Top comments (0)