DesignFoundation
A production-grade SwiftUI design system. Token-based theming, protocol-driven style swapping, first-class Liquid Glass support, and a full component library — one dependency, instantly consistent across every screen.
DesignFoundation mirrors SwiftUI's own ButtonStyle pattern across every component.
Inject a DFTheme once at the app root; every component reads its colors, typography,
spacing, and radius from the nearest theme in the environment. Override any subtree. Write custom styles
by implementing one function. Zero hardcoded values anywhere.
Installation
Xcode
File → Add Package Dependencies, paste the URL below, and choose Up to Next Major from version 1.1.0.
https://github.com/NerdSnipe-Inc/design-foundation
Package.swift
// Package.swift dependencies: [ .package(url: "https://github.com/NerdSnipe-Inc/design-foundation", from: "1.1.0") ], targets: [ .target(name: "YourApp", dependencies: ["DesignFoundation"]) ]
Quick Start
import DesignFoundation @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() .dfTheme(DFTheme(colors: DFColorTokens(primary: .indigo))) } } } // In any view: DFButton("Get Started") { /* action */ } DFTextField("Email", text: $email) .dfTextFieldStyle(.outlined) DFCard { DFText("Hello", scale: .headline) }
DFTheme
A single DFTheme struct propagates through SwiftUI's environment.
Inject it once at the root and every component responds automatically. Override at any subtree depth.
ContentView() .dfTheme(DFTheme( colors: DFColorTokens( primary: .indigo ), spacing: DFSpacingTokens(md: 20), radius: DFRadiusTokens(md: 12) ))
.dfTheme(...) to apply a different palette to just that section (e.g. a dark hero banner inside a light screen).
Tokens
Every component reads exclusively from these token namespaces — no hardcoded values anywhere in the library.
Colors — theme.colors
| Token | Purpose |
|---|---|
| .primary | Brand / interactive accent |
| .surface | Card and panel backgrounds |
| .surfaceElevated | Raised overlays, popovers |
| .textPrimary | Body and heading text |
| .textSecondary | Labels, placeholders, captions |
| .textDisabled | Disabled control labels |
| .border | Strokes, dividers |
| .interactiveFill | Input field backgrounds |
| .destructive | Delete, danger actions |
| .success / .warning / .info | Semantic status colors |
Spacing — theme.spacing
| Token | Default |
|---|---|
| .xs | 4 pt |
| .sm | 8 pt |
| .md | 12 pt |
| .lg | 16 pt |
| .xl | 24 pt |
| .xxl | 32 pt |
Radius — theme.radius
| Token | Default |
|---|---|
| .none | 0 |
| .sm | 4 pt |
| .md | 8 pt |
| .lg | 12 pt |
| .full | 9999 pt (pill) |
Typography — theme.typography
| Token | Usage |
|---|---|
| .display.font | Hero headlines |
| .title.font | Screen titles |
| .headline.font | Section headers |
| .labelLarge.font | Prominent inline labels |
| .body.font | Body text |
| .bodySmall.font | Secondary body text |
| .label.font | Small UI labels |
| .caption.font | Labels, helper text |
Shadows — theme.shadows
| Token | Fields |
|---|---|
| .none / .sm / .md / .lg | Each a DFShadow: color, radius, x, y |
Animation — theme.animation
| Token | Purpose |
|---|---|
| .fast | Quick state changes (press, toggle) |
| .default | Standard transitions |
| .slow | Emphasis / large layout changes |
Per-component overrides — theme.components
Every field is optional — nil inherits the regular tokens above. Confirmed read directly by component styles (e.g. DFButtonStyle reads theme.components.button.cornerRadius ?? theme.radius.md).
| Sub-namespace | Overrides |
|---|---|
| DFButtonTokens | cornerRadius, horizontalPadding, verticalPadding, labelStyle |
| DFTextFieldTokens | cornerRadius, horizontalPadding, verticalPadding, inputStyle, labelStyle |
| DFCardTokens | cornerRadius, padding |
| DFAvatarTokens | defaultSize, borderWidth |
| DFBadgeTokens | cornerRadius, horizontalPadding, verticalPadding |
| DFIconTokens | defaultSize |
Materials — DFMaterialTokens (iOS/macOS 26+)
surfaceMaterial, elevatedMaterial, preferLiquidGlass. Not yet wired into DFTheme — .glass styles currently use .regularMaterial/.thickMaterial directly rather than reading this type. Documented here so you know it exists, not because it configures anything yet.
Preset Themes
Four opinionated visual identities ship in the box — each with a distinct color palette, corner radius scale, and shadow weight. One modifier; automatic light/dark switching.
// Recommended — auto-adapts to system light/dark MyApp() .dfThemePreset(.aurora) // Force a specific variant PreviewView() .dfTheme(.copperDark)
| Preset | Personality | Radius | Shadows | Best for |
|---|---|---|---|---|
| .slate | Professional, balanced | Default (md 8) | Standard | SaaS, developer tools |
| .aurora | Vibrant, creative | Rounded (md 10) | Soft | Creative tools, social |
| .copper | Warm, editorial | Sharp (md 6) | Defined | Finance, content readers |
| .sage | Calm, organic | Very rounded (md 12) | Airy | Health, wellness |
Theme Presets Guide
Full color palettes, radius and shadow specs, API reference, and power-user patterns.
Style System
Every component exposes a style protocol with a single makeBody(configuration:) method —
the same pattern as SwiftUI's ButtonStyle. Styles propagate through the environment,
compose with each other, and apply hierarchically.
// Apply a style to an entire section VStack { ... } .dfButtonStyle(.outlined) .dfCardStyle(.glass) // Override for a single component DFButton("Delete", role: .destructive) { } .dfButtonStyle(.ghost) // Liquid Glass across your whole UI (iOS/macOS 26+) ContentView() .dfButtonStyle(.glass) .dfCardStyle(.glass) .dfTooltipStyle(.glass)
Writing a custom style means implementing one function. All protocols are open; built-in styles are concrete structs you can copy and fork.
struct MyButtonStyle: DFButtonStyle { func makeBody(configuration: DFButtonStyleConfiguration) -> some View { configuration.label .padding(.horizontal, configuration.theme.spacing.lg) .background(configuration.theme.colors.primary) .clipShape(Capsule()) .opacity(configuration.isPressed ? 0.7 : 1) } }
Primitives
| Component | Built-in Styles |
|---|---|
| DFButton | .filled .outlined .ghost .tinted .glass¹ |
| DFText | scale: display, title, headline, labelLarge, body, bodySmall, label, caption |
| DFIcon | SF Symbol wrapper with token-driven size and color |
| DFBadge | .default .subtle .outlined .glass¹ |
| DFAvatar | .circle .rounded .ring .glass¹ — image or initials, presence indicators |
| DFDivider | .standard .thick .subtle — horizontal/vertical, labeled variant |
Inputs
All input components share DFValidationState (.none / .valid / .error(String)) for consistent error display.
| Component | Built-in Styles / Notes |
|---|---|
| DFTextField | .outlined .filled |
| DFSecureField | .outlined .filled — reveal toggle built in |
| DFValidatedTextField | Reads/writes a named field on a DFFormState you register validators on separately — DFRequiredValidator, DFEmailValidator, DFMinLengthValidator, DFMaxLengthValidator, DFRegexValidator, or your own DFFieldValidator. |
| DFToggle | .switch .checkbox .glass¹ |
| DFSlider | .standard .labeled .glass¹ |
| DFPicker | .segmented .menu .wheel .glass¹ |
| DFDatePicker | .compact .graphical .wheel .glass¹ |
| DFCheckbox | .default |
// DFFormState — observable state for a set of validated fields let formState = DFFormState(fields: [ "email": [DFRequiredValidator(), DFEmailValidator()], "password": [DFRequiredValidator(), DFMinLengthValidator(minLength: 8)], ]) DFValidatedTextField("Email", field: "email", form: formState) DFSecureField( "Password", text: formState.binding(for: "password"), validationState: formState.validationState(for: "password") ) DFButton("Sign in") { guard formState.validate() else { return } submit(formState.values["email", default: ""], formState.values["password", default: ""]) }
Layout
| Component | Built-in Styles |
|---|---|
| DFCard | .elevated .outlined .filled .glass¹ |
Overlays
These are applied as view modifiers (.dfModal(), .dfSheet(), .dfPopover(), .dfTooltip()) — not constructed directly like the components above.
| Component | Built-in Styles |
|---|---|
| DFModal | .standard, DFGlassModalStyle()¹² — no .glass shorthand for Modal specifically |
| DFSheet | .standard .compact .glass¹ |
| DFPopover | .arrow .compact .glass¹ |
| DFTooltip | .bubble .glass¹ |
² DFGlassModalStyle exists but has no .glass convenience accessor like the other overlay styles — construct it directly: .dfModalStyle(DFGlassModalStyle()).
Supplementary
| Component | Notes |
|---|---|
| DFAlertConfiguration + .dfAlert() | Convenience wrapper over native SwiftUI alert |
| DFToastQueue + .dfToast() | Queue management and auto-dismiss |
| DFSkeleton | Shimmer animation placeholder |
| DFProgressBar | Linear, circular, and indeterminate variants |
| DFListRow | Leading/trailing slots and disclosure indicator |
| DFList | Swipe-delete, reorder, and multi-select |
| DFTable | Sortable columns |
| DFDataTable | Selection, multi-sort, empty slot — cross-platform |
| DFDataGrid | Inline edit, bulk actions, column config, large-dataset paging |
¹ .glass styles require iOS 26+ / macOS 26+.
Add-on Packages
DesignFoundation is the free, open-source foundation. One commercial package —
DesignFoundationPro — builds on top, adding drop-in blocks for common UI patterns and
full screens for complete vertical feature sets. Both share the same DFTheme
as the free package, so a brand color change ripples through everything identically.
DesignFoundationPro
29 drop-in blocks, 47 production screens across 9 verticals, 18 shell layouts, and 9 wired composition examples. All components adapt to iOS, macOS, and visionOS automatically — no platform guards required.
DFPlayground — See it before you build it
Free macOS companion app with every component, block, screen, and theme interactive and live. Browse the full catalog, switch themes, open any Pro screen — then decide what to use.
Installation
Add DesignFoundation via SPM (free). Pro is a licensed add-on — private repo access provided after purchase:
// Package.swift — Foundation (public) dependencies: [ .package(url: "https://github.com/NerdSnipe-Inc/design-foundation", from: "1.1.0"), // Pro: private SPM URL included with your license ]
Platforms
| Platform | Minimum Version |
|---|---|
| iOS | 18.0 |
| macOS | 15.0 |
| visionOS | 2.0 |
.glass styles require iOS 26+ / macOS 26+. All other styles work on the minimum versions above.
How "no platform guards" actually works: DFPlatformContext — a resolved-once struct (idiom, horizontalSizeClass, isLiquidGlassAvailable) — is injected into the SwiftUI environment alongside DFTheme by .dfTheme()/.dfThemePreset(). Component styles read this context internally to pick their rendering path, instead of your app branching on platform with #if os().
License
MIT © 2026 NerdSnipe Inc. DesignFoundation is free and open-source. View LICENSE →