Getting Started/Configuration

Configuration

SwiftDS works out of the box with zero configuration. If you want to customise colours, spacing, typography, or animations to match your brand, all changes happen in one place — the DSTokens.swift file.

How tokens work

Every component in the system reads from the token enums — never from hardcoded values. This means you can change your brand colour once in DSColor and it will propagate instantly to every button, input, badge, and chart across the entire app.

DSTokens.swift — DSColor (customise your brand)
public enum DSColor {
    // ── Brand ──────────────────────────────────────────
    // Change these two values to apply your brand palette
    public static let primary   = Color(hex: "#6366F1")  // Indigo — your main brand colour
    public static let accent    = Color(hex: "#EC4899")  // Pink   — secondary accent

    // ── Semantic (do not change unless intentional) ────
    public static let success   = Color(hex: "#22C55E")
    public static let warning   = Color(hex: "#F59E0B")
    public static let error     = Color(hex: "#EF4444")
    public static let info      = Color(hex: "#3B82F6")

    // ── Adaptive (light / dark auto) ───────────────────
    public static var background: Color { Color("DSBackground") }
    public static var surface:    Color { Color("DSSurface") }
    public static var textPrimary:    Color { Color("DSTextPrimary") }
    public static var textSecondary:  Color { Color("DSTextSecondary") }
    public static var border:     Color { Color("DSBorder") }
}

Customising spacing

The spacing scale follows a 4pt baseline grid. If your product uses a different base unit (e.g. 8pt), change the base multipliers in DSSpacing.

DSTokens.swift — DSSpacing
public enum DSSpacing {
    public static let xs  : CGFloat = 4   // 1 unit
    public static let sm  : CGFloat = 8   // 2 units
    public static let md  : CGFloat = 16  // 4 units  ← default gap
    public static let lg  : CGFloat = 24  // 6 units
    public static let xl  : CGFloat = 32  // 8 units
    public static let xxl : CGFloat = 48  // 12 units

    // Usage:
    // VStack(spacing: DSSpacing.md) { ... }
    // .padding(DSSpacing.xl)
}

Customising border radius

DSTokens.swift — DSRadius
public enum DSRadius {
    public static let sm  : CGFloat = 6   // inputs, tags
    public static let md  : CGFloat = 10  // buttons, cards
    public static let lg  : CGFloat = 16  // modals, bottom sheets
    public static let xl  : CGFloat = 24  // large cards, onboarding screens
    public static let full: CGFloat = 999 // pills, badges, avatars
}

Customising animations

All animations use Animation.spring(). Adjusting response and damping lets you make interactions feel snappier or more fluid.

DSTokens.swift — DSAnimation
public enum DSAnimation {
    // ── Interactive (buttons, toggles) ─────────────────
    public static let interactive = Animation.spring(
        response: 0.3,   // lower = snappier
        dampingFraction: 0.7
    )
    // ── Smooth (modals, sheets) ────────────────────────
    public static let smooth = Animation.spring(
        response: 0.45,
        dampingFraction: 0.82
    )
    // ── Gentle (list items, fades) ─────────────────────
    public static let gentle = Animation.spring(
        response: 0.55,
        dampingFraction: 0.9
    )
    // ── Quick (toasts, tooltips) ───────────────────────
    public static let quick = Animation.easeOut(duration: 0.18)
}

Dark mode

SwiftDS uses adaptive Color assets and @Environment(\.colorScheme) internally. No additional setup is required — dark mode is automatic.

To force a specific mode in a subtree (e.g. always dark in a preview card), use the standard SwiftUI modifier:

Force a colour scheme on a subtree
DSCard {
    PreviewContent()
}
.preferredColorScheme(.dark) // always dark regardless of system setting

Building Your First Screen

Let's build a complete profile screen using SwiftDS components. This example demonstrates how to combine multiple components with proper spacing and layout:

ProfileScreen.swift — Complete example
import SwiftUI
import SwiftDS

struct ProfileScreen: View {
    @State private var name = "John Doe"
    @State private var email = "john@example.com"
    @State private var bio = ""
    @State private var notificationsEnabled = true
    @State private var darkModeEnabled = false
    
    var body: some View {
        ScrollView {
            VStack(spacing: DSSpacing.xl) {
                // Header
                VStack(spacing: DSSpacing.md) {
                    DSAvatar(name: name, size: .xl)
                    
                    Text(name)
                        .font(DSTypography.title2)
                        .foregroundColor(.dsForeground)
                    
                    Text(email)
                        .font(DSTypography.body)
                        .foregroundColor(.dsForegroundMuted)
                }
                .padding(.top, DSSpacing.xl)
                
                // Profile Info Card
                DSCard {
                    VStack(alignment: .leading, spacing: DSSpacing.md) {
                        Text("Profile Information")
                            .font(DSTypography.headline)
                        
                        DSTextField(
                            label: "Name",
                            placeholder: "Your name",
                            text: $name
                        )
                        
                        DSTextField(
                            label: "Email",
                            placeholder: "your@email.com",
                            text: $email,
                            leadingIcon: "envelope"
                        )
                        
                        DSTextArea(
                            label: "Bio",
                            placeholder: "Tell us about yourself...",
                            text: $bio,
                            minHeight: 100
                        )
                    }
                }
                
                // Settings Card
                DSCard {
                    VStack(alignment: .leading, spacing: DSSpacing.md) {
                        Text("Preferences")
                            .font(DSTypography.headline)
                        
                        HStack {
                            VStack(alignment: .leading) {
                                Text("Notifications")
                                    .font(DSTypography.body)
                                Text("Receive push notifications")
                                    .font(DSTypography.caption)
                                    .foregroundColor(.dsForegroundMuted)
                            }
                            Spacer()
                            DSToggle(isOn: $notificationsEnabled)
                        }
                        
                        Divider()
                        
                        HStack {
                            VStack(alignment: .leading) {
                                Text("Dark Mode")
                                    .font(DSTypography.body)
                                Text("Use dark theme")
                                    .font(DSTypography.caption)
                                    .foregroundColor(.dsForegroundMuted)
                            }
                            Spacer()
                            DSToggle(isOn: $darkModeEnabled)
                        }
                    }
                }
                
                // Actions
                VStack(spacing: DSSpacing.sm) {
                    DSButton(
                        "Save Changes",
                        variant: .primary,
                        size: .lg,
                        isFullWidth: true
                    ) {
                        saveProfile()
                    }
                    
                    DSButton(
                        "Sign Out",
                        variant: .ghost,
                        size: .md,
                        isFullWidth: true
                    ) {
                        signOut()
                    }
                }
            }
            .padding(DSSpacing.lg)
        }
    }
    
    private func saveProfile() {
        print("Profile saved")
    }
    
    private func signOut() {
        print("Signed out")
    }
}

#Preview {
    ProfileScreen()
}

What We Used

  • DSAvatar - User profile picture with fallback
  • DSCard - Content containers with elevation
  • DSTextField - Text inputs with labels and icons
  • DSTextArea - Multi-line text input
  • DSToggle - On/off switches for settings
  • DSButton - Primary and ghost button variants
  • DSSpacing - Consistent spacing tokens throughout
  • DSTypography - Typography scale for text hierarchy

Using the Showcase app

The package includes two Showcase apps that let you browse all components interactively directly in Xcode Previews or the Simulator:

Open in Xcode Previews
// In DSShowcaseApp.swift — base components (buttons, inputs, cards...)
#Preview {
    DSShowcaseApp()
}

// In DSAdvancedShowcase.swift — product components (analytics, onboarding...)
#Preview {
    DSAdvancedShowcaseApp()
}