Skip to content

Getting Started

Daniel S edited this page Jul 2, 2026 · 1 revision

Getting Started

DesignFoundation is a token-based SwiftUI design system. One DFTheme value lives in the SwiftUI environment, every component beneath it reads from that theme, and a brand update becomes a single-line change. This page walks you through installing the package, applying a theme, writing your first view, and understanding how the token system works.


Requirements

Requirement Minimum
Swift 6.0 (strict concurrency enabled)
iOS 18.0
macOS 15.0
visionOS 2.0
Xcode 16.0

The package is Swift 6 strict-concurrency-safe. All public types that cross concurrency boundaries conform to Sendable. No @unchecked Sendable workarounds are needed in client code for normal usage.

Liquid Glass styles (.glass variants on DFButton, DFCard, DFModal, and others) require iOS 26+ / macOS 26+. All other functionality works on the minimum versions above.


Installation

Xcode (recommended)

  1. Open your project in Xcode.
  2. Choose File → Add Package Dependencies…
  3. Paste the repository URL into the search field:
    https://github.com/NerdSnipe-Inc/design-foundation
    
  4. Set the dependency rule to Up to Next Major Version, starting from 1.0.0.
  5. Click Add Package.
  6. In the target selection sheet, tick DesignFoundation next to your app target and click Add Package.

Package.swift

// swift-tools-version: 6.0
import PackageDescription

let package = Package(
    name: "MyApp",
    platforms: [
        .iOS(.v18),
        .macOS(.v15),
        .visionOS(.v2),
    ],
    dependencies: [
        .package(
            url: "https://github.com/NerdSnipe-Inc/design-foundation",
            from: "1.0.0"
        ),
    ],
    targets: [
        .target(
            name: "MyApp",
            dependencies: [
                .product(name: "DesignFoundation", package: "design-foundation")
            ]
        ),
    ]
)

After resolving the package, import the module in any Swift file where you need it:

import DesignFoundation

Theme Architecture Overview

DFTheme is a value type (struct) that aggregates seven token namespaces:

Namespace Type Purpose
colors DFColorTokens Brand, surface, text, interactive, and feedback colors
typography DFTypographyTokens Font, line spacing, and tracking for each text role
spacing DFSpacingTokens Six named spacing steps from xs (4 pt) to xxl (32 pt)
radius DFRadiusTokens Five named corner-radius steps from none to full
shadows DFShadowTokens Four named shadow levels from none to lg
animation DFAnimationTokens Three named easing curves: fast, default, slow
components DFComponentTokens Per-component overrides for button, text field, card, avatar, badge, and icon

A DFTheme is injected into the SwiftUI environment with the .dfTheme(_:) modifier. Every DesignFoundation component reads from @Environment(\.dfTheme). Change a token, every component that uses it updates — no manual wiring.

DFThemePreset pairs a light DFTheme with a dark DFTheme and provides the .dfThemePreset(_:) convenience modifier, which resolves the correct variant automatically based on @Environment(\.colorScheme).


Applying a Theme at the Scene Root

Using a preset (recommended starting point)

import SwiftUI
import DesignFoundation

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .dfThemePreset(.slate)
        }
    }
}

Using a named theme directly

SomeSubView()
    .dfTheme(.auroraDark)

Building a custom theme

let brandTheme = DFTheme(
    colors: DFColorTokens(
        primary: Color(red: 0.2, green: 0.4, blue: 0.9),
        accent: .orange
    ),
    radius: DFRadiusTokens(md: 16, lg: 24),
    spacing: DFSpacingTokens(lg: 20, xl: 28)
)

ContentView()
    .dfTheme(brandTheme)

Mutating a single token from a preset

var theme = DFTheme.sageLight
theme.colors.primary = .purple
theme.radius.md = 20

MyView().dfTheme(theme)

Preset Reference

Four presets ship in the box. Each one defines distinct color tokens, corner-radius tokens, and shadow tokens tuned to its visual personality.

.slate — Professional, neutral

A cool blue-grey palette built for interfaces that need to communicate competence without asserting a strong brand color.

ContentView().dfThemePreset(.slate)

Fits well with: SaaS dashboards, developer tools, productivity apps, admin interfaces.

.aurora — Vibrant, expressive

A violet primary color with softer, more diffuse shadows and slightly larger corner radii (md: 10, lg: 16).

ContentView().dfThemePreset(.aurora)

Fits well with: creative tools, social apps, design utilities, consumer entertainment.

.copper — Warm, grounded

Earthy orange-brown primary with tight corner radii (md: 6, lg: 10) and heavier drop shadows.

ContentView().dfThemePreset(.copper)

Fits well with: finance apps, reading apps, editorial products, content-heavy interfaces.

.sage — Calm, natural

A muted green palette with the most generous corner radii of any preset (md: 12, lg: 18, full: 9999) and the lightest shadows.

ContentView().dfThemePreset(.sage)

Fits well with: health, wellness, journaling, meditation, focus apps.


A Minimal App

import SwiftUI
import DesignFoundation

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .dfThemePreset(.slate)
        }
    }
}

struct ContentView: View {
    @State private var count = 0

    var body: some View {
        DFCard {
            VStack(alignment: .leading, spacing: 16) {
                DFText("Hello, DesignFoundation", style: .headline)
                DFText("Tap the button to increment the counter.", style: .body)

                DFText("Count: \(count)", style: .title)
                    .frame(maxWidth: .infinity, alignment: .center)

                DFButton("Increment") {
                    count += 1
                }
            }
        }
        .padding()
    }
}

Accessing Theme Tokens in Custom Views

import SwiftUI
import DesignFoundation

struct StatusDot: View {
    enum Status { case active, idle, error }

    let status: Status

    @Environment(\.dfTheme) private var theme

    var body: some View {
        Circle()
            .fill(dotColor)
            .frame(width: 10, height: 10)
    }

    private var dotColor: Color {
        switch status {
        case .active: return theme.colors.success
        case .idle:   return theme.colors.textSecondary
        case .error:  return theme.colors.destructive
        }
    }
}

Token namespaces quick reference

theme.colors — primary, secondary, accent, background, surface, surfaceElevated, textPrimary, textSecondary, textDisabled, border, interactiveFill, interactiveHover, interactivePressed, interactiveDisabled, destructive, success, warning, info

theme.spacing — xs (4 pt), sm (8 pt), md (12 pt), lg (16 pt), xl (24 pt), xxl (32 pt)

theme.radius — none (0), sm (4 pt), md (8 pt), lg (12 pt), full (9999 pt)

theme.typography — display, title, headline, body, label, caption — each a DFTextStyle with .font, .lineSpacing, .tracking

theme.shadows — none, sm, md, lg — each a DFShadow with .color, .radius, .x, .y

theme.animation — fast (0.15s easeInOut), default (0.25s easeInOut), slow (0.40s easeInOut)


Dark Mode

When you apply .dfThemePreset(_:), the modifier reads @Environment(\.colorScheme) internally and selects the correct light or dark variant. When the user toggles appearance, SwiftUI invalidates views and the modifier re-runs, injecting the updated theme. All components and custom views reading @Environment(\.dfTheme) update automatically.

#Preview("Light") {
    ContentView().dfTheme(.slateLight)
}

#Preview("Dark") {
    ContentView().dfTheme(.slateDark)
}

Next Steps

Clone this wiki locally