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.
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.
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
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.
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:
DSCard {
PreviewContent()
}
.preferredColorScheme(.dark) // always dark regardless of system settingBuilding 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:
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:
// In DSShowcaseApp.swift — base components (buttons, inputs, cards...)
#Preview {
DSShowcaseApp()
}
// In DSAdvancedShowcase.swift — product components (analytics, onboarding...)
#Preview {
DSAdvancedShowcaseApp()
}