Agent skill
swiftui-colors-modifiers
Modern SwiftUI colors, ShapeStyle, gradients, MeshGradient, and custom ViewModifiers. Use when user asks about colors, foregroundStyle, gradients, hierarchical colors, tint, custom ViewModifiers, or SwiftUI styling.
Stars
163
Forks
31
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/swiftui-colors-modifiers
SKILL.md
SwiftUI Colors and Modifiers
Comprehensive guide to modern SwiftUI color APIs, ShapeStyle, gradients, and creating reusable ViewModifiers for iOS 26.
Prerequisites
- iOS 15+ for foregroundStyle (iOS 26 recommended)
- Xcode 26+
Modern Color APIs
foregroundStyle (Recommended)
Replaces the deprecated foregroundColor(_:):
swift
// DEPRECATED
Text("Hello")
.foregroundColor(.blue)
// MODERN - Use foregroundStyle
Text("Hello")
.foregroundStyle(.blue)
// With gradients
Text("Gradient Text")
.foregroundStyle(
LinearGradient(
colors: [.blue, .purple],
startPoint: .leading,
endPoint: .trailing
)
)
ShapeStyle Protocol
foregroundStyle accepts any ShapeStyle:
swift
// Colors
.foregroundStyle(.red)
.foregroundStyle(Color.blue)
// Gradients
.foregroundStyle(LinearGradient(...))
.foregroundStyle(RadialGradient(...))
.foregroundStyle(AngularGradient(...))
.foregroundStyle(MeshGradient(...))
// Materials
.foregroundStyle(.ultraThinMaterial)
.foregroundStyle(.regularMaterial)
// Hierarchical
.foregroundStyle(.primary)
.foregroundStyle(.secondary)
.foregroundStyle(.tertiary)
Hierarchical Colors
Setting Hierarchy at Root
swift
// Set all three levels at once
ContentView()
.foregroundStyle(.red, .orange, .yellow)
// Children use hierarchical levels
struct ContentView: View {
var body: some View {
VStack {
Text("Primary") // Red
.foregroundStyle(.primary)
Text("Secondary") // Orange
.foregroundStyle(.secondary)
Text("Tertiary") // Yellow
.foregroundStyle(.tertiary)
}
}
}
Available Levels
swift
.foregroundStyle(.primary) // Level 1 - Most prominent
.foregroundStyle(.secondary) // Level 2
.foregroundStyle(.tertiary) // Level 3
.foregroundStyle(.quaternary) // Level 4
.foregroundStyle(.quinary) // Level 5 - Least prominent
Note: Only first three can be customized via foregroundStyle(_:_:_:).
Practical Example
swift
struct CardView: View {
let title: String
let subtitle: String
let detail: String
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(title)
.font(.headline)
.foregroundStyle(.primary)
Text(subtitle)
.font(.subheadline)
.foregroundStyle(.secondary)
Text(detail)
.font(.caption)
.foregroundStyle(.tertiary)
}
}
}
Semantic Colors
System Colors
swift
// Adaptive colors (change with Dark Mode)
Color.primary // Black/White
Color.secondary // Gray
Color.accentColor // App's accent color
// UI element colors
Color(uiColor: .systemBackground)
Color(uiColor: .secondarySystemBackground)
Color(uiColor: .tertiarySystemBackground)
Color(uiColor: .label)
Color(uiColor: .secondaryLabel)
Accent Color
Set in Asset Catalog or programmatically:
swift
// In code
Button("Action") { }
.tint(.blue)
// App-wide in Assets.xcassets:
// Create "AccentColor" color set
Tint Modifier
Override accent color for a hierarchy:
swift
// tint affects interactive elements, not all foreground
VStack {
Button("Blue") { } // Uses blue tint
Link("Website", destination: url) // Uses blue tint
Text("Plain") // NOT affected by tint
}
.tint(.blue)
tint vs foregroundStyle:
tint: Affects buttons, links, controlsforegroundStyle: Affects all foreground content
Gradients
LinearGradient
swift
LinearGradient(
colors: [.blue, .purple],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
// With stops for control
LinearGradient(
stops: [
.init(color: .red, location: 0),
.init(color: .orange, location: 0.3),
.init(color: .yellow, location: 1)
],
startPoint: .top,
endPoint: .bottom
)
// Usage
Rectangle()
.fill(
LinearGradient(
colors: [.blue, .cyan],
startPoint: .leading,
endPoint: .trailing
)
)
RadialGradient
swift
RadialGradient(
colors: [.white, .blue],
center: .center,
startRadius: 0,
endRadius: 200
)
// With offset center
RadialGradient(
colors: [.yellow, .orange, .red],
center: .topLeading,
startRadius: 50,
endRadius: 300
)
AngularGradient
swift
AngularGradient(
colors: [.red, .yellow, .green, .blue, .purple, .red],
center: .center
)
// Conic gradient with angle
AngularGradient(
colors: [.blue, .purple],
center: .center,
startAngle: .degrees(0),
endAngle: .degrees(180)
)
MeshGradient (iOS 18+)
Complex multi-point gradients:
swift
MeshGradient(
width: 3,
height: 3,
points: [
// Row 0
[0.0, 0.0], [0.5, 0.0], [1.0, 0.0],
// Row 1
[0.0, 0.5], [0.5, 0.5], [1.0, 0.5],
// Row 2
[0.0, 1.0], [0.5, 1.0], [1.0, 1.0]
],
colors: [
.red, .orange, .yellow,
.green, .blue, .purple,
.pink, .cyan, .mint
]
)
// Animated mesh
struct AnimatedMesh: View {
@State private var offset: CGFloat = 0
var body: some View {
MeshGradient(
width: 3,
height: 3,
points: [
[0.0, 0.0], [0.5, 0.0], [1.0, 0.0],
[0.0, 0.5], [0.5 + offset, 0.5], [1.0, 0.5],
[0.0, 1.0], [0.5, 1.0], [1.0, 1.0]
],
colors: [
.blue, .cyan, .teal,
.purple, .indigo, .blue,
.pink, .orange, .yellow
],
smoothsColors: true
)
.onAppear {
withAnimation(.easeInOut(duration: 2).repeatForever()) {
offset = 0.2
}
}
}
}
Asset Catalog Colors
Creating Color Sets
- Open Assets.xcassets
- Right-click → New Color Set
- Configure for appearances:
- Any Appearance
- Light
- Dark
- High Contrast variants
Using Asset Colors
swift
// By name
Color("BrandPrimary")
Color("BackgroundColor")
// With bundle
Color("CustomColor", bundle: .module)
Organizing Colors
Assets.xcassets/
├── Colors/
│ ├── Brand/
│ │ ├── BrandPrimary
│ │ ├── BrandSecondary
│ │ └── BrandAccent
│ ├── UI/
│ │ ├── BackgroundPrimary
│ │ ├── BackgroundSecondary
│ │ └── SeparatorColor
│ └── Text/
│ ├── TextPrimary
│ ├── TextSecondary
│ └── TextTertiary
Custom ShapeStyles (iOS 17+)
swift
struct StripedStyle: ShapeStyle {
var color1: Color
var color2: Color
var stripeWidth: CGFloat
func resolve(in environment: EnvironmentValues) -> some ShapeStyle {
// Return a resolved style
LinearGradient(
stops: generateStripeStops(),
startPoint: .leading,
endPoint: .trailing
)
}
private func generateStripeStops() -> [Gradient.Stop] {
var stops: [Gradient.Stop] = []
var position: CGFloat = 0
while position < 1 {
stops.append(.init(color: color1, location: position))
stops.append(.init(color: color1, location: position + stripeWidth / 2))
stops.append(.init(color: color2, location: position + stripeWidth / 2))
stops.append(.init(color: color2, location: position + stripeWidth))
position += stripeWidth
}
return stops
}
}
// Usage
Rectangle()
.fill(StripedStyle(color1: .blue, color2: .white, stripeWidth: 0.1))
Custom ViewModifiers
Basic Modifier
swift
struct CardStyle: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(.regularMaterial)
.clipShape(RoundedRectangle(cornerRadius: 12))
.shadow(radius: 4)
}
}
extension View {
func cardStyle() -> some View {
modifier(CardStyle())
}
}
// Usage
Text("Card Content")
.cardStyle()
Configurable Modifier
swift
struct RoundedStyle: ViewModifier {
var cornerRadius: CGFloat
var backgroundColor: Color
var shadowRadius: CGFloat
func body(content: Content) -> some View {
content
.padding()
.background(backgroundColor)
.clipShape(RoundedRectangle(cornerRadius: cornerRadius))
.shadow(radius: shadowRadius)
}
}
extension View {
func rounded(
cornerRadius: CGFloat = 12,
backgroundColor: Color = .white,
shadowRadius: CGFloat = 4
) -> some View {
modifier(RoundedStyle(
cornerRadius: cornerRadius,
backgroundColor: backgroundColor,
shadowRadius: shadowRadius
))
}
}
// Usage
Text("Custom")
.rounded(cornerRadius: 20, backgroundColor: .blue)
Environment-Aware Modifier
swift
struct AdaptiveCard: ViewModifier {
@Environment(\.colorScheme) var colorScheme
func body(content: Content) -> some View {
content
.padding()
.background(colorScheme == .dark ? Color.gray.opacity(0.2) : Color.white)
.clipShape(RoundedRectangle(cornerRadius: 12))
.shadow(
color: colorScheme == .dark ? .clear : .black.opacity(0.1),
radius: 8
)
}
}
Conditional Modifier
swift
extension View {
@ViewBuilder
func `if`<Content: View>(
_ condition: Bool,
transform: (Self) -> Content
) -> some View {
if condition {
transform(self)
} else {
self
}
}
@ViewBuilder
func ifLet<T, Content: View>(
_ value: T?,
transform: (Self, T) -> Content
) -> some View {
if let value {
transform(self, value)
} else {
self
}
}
}
// Usage
Text("Hello")
.if(isHighlighted) { view in
view.foregroundStyle(.yellow)
}
.ifLet(user) { view, user in
view.badge(user.notificationCount)
}
iOS 26 New Modifiers
Close Button Role
swift
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Dismiss", role: .close) {
dismiss()
}
// Renders as glass X button
}
}
Glass Button Styles
swift
Button("Glass") { }
.buttonStyle(.glass)
Button("Prominent") { }
.buttonStyle(.glassProminent)
Custom Slider Ticks
swift
Slider(value: $value, in: 0...100) {
Text("Value")
} minimumValueLabel: {
Text("0")
} maximumValueLabel: {
Text("100")
}
.sliderStyle(.ticked(count: 10)) // iOS 26
Design System Example
swift
// DesignSystem.swift
enum DS {
enum Colors {
static let primary = Color("Primary")
static let secondary = Color("Secondary")
static let background = Color("Background")
static let surface = Color("Surface")
static let error = Color("Error")
static let success = Color("Success")
}
enum Spacing {
static let xs: CGFloat = 4
static let sm: CGFloat = 8
static let md: CGFloat = 16
static let lg: CGFloat = 24
static let xl: CGFloat = 32
}
enum CornerRadius {
static let sm: CGFloat = 4
static let md: CGFloat = 8
static let lg: CGFloat = 16
static let xl: CGFloat = 24
}
}
// Modifiers using design system
struct DSCard: ViewModifier {
func body(content: Content) -> some View {
content
.padding(DS.Spacing.md)
.background(DS.Colors.surface)
.clipShape(RoundedRectangle(cornerRadius: DS.CornerRadius.lg))
}
}
extension View {
func dsCard() -> some View {
modifier(DSCard())
}
}
Best Practices
- Use foregroundStyle - Not deprecated foregroundColor
- Leverage Hierarchical Colors - .primary, .secondary, .tertiary
- Asset Catalog for Themes - Organize colors properly
- DRY with Modifiers - Create reusable ViewModifiers
- Compose Modifiers - Build complex styles from simple ones
- Environment Awareness - Respect colorScheme and accessibility
Official Resources
Didn't find tool you were looking for?