Theming
PrettyUI features a powerful, environment-based theming system that makes it easy to create consistent, beautiful interfaces across your entire app.
How Theming Works
Themes in PrettyUI are applied using a view modifier that propagates through the SwiftUI environment. Every PrettyUI component automatically picks up the current theme's colors, spacing, typography, and shadows.
ContentView()
.prettyTheme(.sky) // Apply theme to entire view hierarchy
Built-in Themes
PrettyUI comes with 4 professionally designed themes, each with carefully crafted light and dark mode variants.
Sky
The default theme featuring a vibrant cyan-blue primary color. Perfect for social and communication apps.
.prettyTheme(.sky)
| Token | Light Mode | Dark Mode |
|---|---|---|
| Primary | #1DA1F2 | #1DA1F2 |
| Background | #F8F9FA | #0D0D0D |
| Card | #FFFFFF | #1C1C1E |
| Border | #E8EAED | #38383A |
Indigo
A theme with vibrant purple/indigo accent colors. Ideal for productivity and finance apps.
.prettyTheme(.indigo)
| Token | Light Mode | Dark Mode |
|---|---|---|
| Primary | #6366F1 | #818CF8 |
| Background | #FFFFFF | #0F0D1A |
| Card | #FFFFFF | #1E1B4B |
| Border | #E5E7EB | #312E81 |
Emerald
A theme with refreshing teal/emerald colors. Great for health and nature apps.
.prettyTheme(.emerald)
| Token | Light Mode | Dark Mode |
|---|---|---|
| Primary | #10B981 | #34D399 |
| Background | #FFFFFF | #022C22 |
| Card | #FFFFFF | #064E3B |
| Border | #D1D5DB | #065F46 |
Amber
A warm theme with orange/amber accents. Perfect for creative and entertainment apps.
.prettyTheme(.amber)
| Token | Light Mode | Dark Mode |
|---|---|---|
| Primary | #F59E0B | #FBBF24 |
| Background | #FFFBEB | #1C1917 |
| Card | #FFFFFF | #292524 |
| Border | #FDE68A | #92400E |
Applying Themes
App-Wide Theme
Apply a theme at the root of your app to affect all views:
import SwiftUI
import PrettyUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.prettyTheme(.sky)
}
}
}
Per-View Themes
You can apply different themes to specific views:
struct ContentView: View {
var body: some View {
HStack {
// Sky-themed sidebar
Sidebar()
.prettyTheme(.sky)
// Indigo-themed content
MainContent()
.prettyTheme(.indigo)
}
}
}
Dynamic Theme Switching
Change themes at runtime using state:
struct SettingsView: View {
@AppStorage("selectedTheme") private var themeName = "sky"
var currentTheme: PrettyTheme {
switch themeName {
case "indigo": return .indigo
case "emerald": return .emerald
case "amber": return .amber
default: return .sky
}
}
var body: some View {
VStack {
Picker("Theme", selection: $themeName) {
Text("Sky").tag("sky")
Text("Indigo").tag("indigo")
Text("Emerald").tag("emerald")
Text("Amber").tag("amber")
}
.pickerStyle(.segmented)
}
.prettyTheme(currentTheme)
}
}
Creating Custom Themes
You can create your own theme by configuring color tokens, spacing, radius, shadows, and component configs.
Basic Custom Theme
extension PrettyTheme {
static let myCustomTheme = PrettyTheme(
colors: ColorTokens(
primary: Color(hex: "#FF6B6B"),
primaryForeground: Color(hex: "#FFFFFF"),
secondary: Color(hex: "#FFE8E8"),
secondaryForeground: Color(hex: "#9B2C2C"),
accent: Color(hex: "#FF8787"),
accentForeground: Color(hex: "#FFFFFF"),
destructive: Color(hex: "#EF4444"),
destructiveForeground: Color(hex: "#FFFFFF"),
success: Color(hex: "#22C55E"),
successForeground: Color(hex: "#FFFFFF"),
warning: Color(hex: "#F59E0B"),
warningForeground: Color(hex: "#18181B"),
background: Color(hex: "#FFFFFF"),
foreground: Color(hex: "#1A1A1A"),
muted: Color(hex: "#F5F5F5"),
mutedForeground: Color(hex: "#6B7280"),
card: Color(hex: "#FFFFFF"),
cardForeground: Color(hex: "#1A1A1A"),
border: Color(hex: "#E5E5E5"),
input: Color(hex: "#E5E5E5"),
ring: Color(hex: "#FF6B6B")
)
)
}
// Usage
ContentView()
.prettyTheme(.myCustomTheme)
Theme with Dark Mode
extension PrettyTheme {
static let coral = PrettyTheme(
colors: ColorTokens(
primary: Color(hex: "#FF6B6B"),
// ... light mode colors
),
darkColors: ColorTokens(
primary: Color(hex: "#FF8787"),
// ... dark mode colors
)
)
}
Theme with Custom Component Configs
Customize how specific components look and behave:
extension PrettyTheme {
static let rounded = PrettyTheme(
colors: .light,
radius: RadiusTokens(
none: 0,
sm: 8,
md: 12,
lg: 16,
xl: 24,
xxl: 32,
full: 9999
),
components: ComponentConfigs(
button: ButtonConfig(
defaultVariant: .primary,
defaultSize: .lg,
radius: .full, // Pill-shaped buttons
animationDuration: 0.25,
showPressAnimation: true
),
card: CardConfig(
radius: .xxl, // Extra rounded cards
shadow: .md,
padding: .lg,
showBorder: false,
borderWidth: 0
)
)
)
}
Accessing Theme Values
Access the current theme in your custom views:
struct CustomView: View {
@Environment(\.prettyTheme) private var theme
@Environment(\.colorScheme) private var colorScheme
var body: some View {
let colors = theme.colors(for: colorScheme)
Rectangle()
.fill(colors.primary)
.frame(width: theme.spacing.lg, height: theme.spacing.lg)
.cornerRadius(theme.radius.md)
.shadow(
color: theme.shadows.md.color,
radius: theme.shadows.md.radius,
x: theme.shadows.md.x,
y: theme.shadows.md.y
)
}
}
Best Practices
- Apply themes at the root — Set your theme at the app level for consistency
- Use semantic colors — Use
primary,success,warning,destructiveinstead of hardcoded colors - Support both color schemes — Always provide
darkColorsfor a complete experience - Test all themes — If supporting multiple themes, test each one thoroughly
- Keep it simple — Start with built-in themes before creating custom ones