SwiftUI Design Tokens & Theming System (Production-Scale)

Published: (January 1, 2026 at 01:43 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

As SwiftUI apps grow, UI consistency becomes fragile. You start seeing:

  • slightly different padding values
  • inconsistent corner radii
  • random colors hard‑coded 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, and 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: AppColor.Type
    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 based on:

  • system appearance
  • accessibility settings
  • 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.

Back to Blog

Related posts

Read more »

SwiftUI Accessibility Internals

Accessibility Is a Parallel View Tree SwiftUI builds two trees: - The visual view tree - The accessibility tree They are related — but not identical. A single...

SwiftUI Gesture System Internals

markdown !Sebastien Latohttps://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%...

SwiftUI View Diffing & Reconciliation

SwiftUI doesn’t “redraw the screen”. It diffs view trees. If you don’t understand how SwiftUI decides what changed vs what stayed the same, you’ll see unnecessa...