SwiftUI Color Swatch Picker Component
A swatch grid. Use this instead of the system ColorPicker when you have a fixed brand palette — an eyedropper and an infinite colour wheel are the wrong affordance for "pick one of our eight accent colours".
Install the free SwiftUI color swatch picker
- Add SwiftKitUI.swift to your app once. It holds the tokens and motion curves.
- Copy SKColorSwatchPicker.swift below into your project. It needs nothing else.
Usage
Usage.swift
SKColorSwatchPicker(selection: $accent, colors: brandColors)Full source · 103 lines · MIT
SKColorSwatchPicker.swift
//
// SKColorSwatchPicker.swift
// Swift Kit UI
//
// Requires: SwiftKitUI.swift
//
// A swatch grid. Use this instead of the system ColorPicker when you have a
// fixed brand palette — an eyedropper and an infinite colour wheel are the
// wrong affordance for "pick one of our eight accent colours".
//
// Usage:
// SKColorSwatchPicker(selection: $accent, colors: brandColors)
//
import SwiftUI
public struct SKColorSwatchPicker: View {
@Binding private var selection: Color
private let colors: [Color]
private let columns: Int
private let size: CGFloat
@Environment(\.accessibilityReduceMotion) private var reduceMotion
public init(
selection: Binding<Color>,
colors: [Color],
columns: Int = 6,
size: CGFloat = 44
) {
self._selection = selection
self.colors = colors
self.columns = columns
self.size = size
}
public var body: some View {
LazyVGrid(
columns: Array(repeating: GridItem(.flexible(), spacing: SK.Space.md), count: columns),
spacing: SK.Space.md
) {
ForEach(Array(colors.enumerated()), id: \.offset) { _, color in
swatch(color)
}
}
.accessibilityElement(children: .contain)
}
private func swatch(_ color: Color) -> some View {
let isSelected = color == selection
return Button {
withAnimation(SKMotion.pop.resolved(reduceMotion: reduceMotion)) {
selection = color
}
SK.Haptic.play(.selection)
} label: {
Circle()
.fill(color)
.frame(width: size, height: size)
.overlay {
Circle().strokeBorder(.white.opacity(0.5), lineWidth: SK.Stroke.thin)
}
.overlay {
if isSelected {
Image(systemName: "checkmark")
.font(SK.Icon.symbol(SK.Icon.sm, weight: .bold))
.foregroundStyle(.white)
.shadow(color: .black.opacity(0.35), radius: 2)
}
}
// A ring outside the swatch rather than a border on it, so the
// colour being chosen is never altered by its own selection UI.
.overlay {
Circle()
.strokeBorder(SK.Palette.accent, lineWidth: isSelected ? 3 : 0)
.padding(-5)
}
.scaleEffect(isSelected ? 1.06 : 1)
.contentShape(.circle)
}
.buttonStyle(.skPress(scale: 0.9, haptic: nil))
.skAnimation(.snap, value: isSelected)
.accessibilityAddTraits(isSelected ? [.isButton, .isSelected] : .isButton)
}
}
#Preview("SKColorSwatchPicker") {
@Previewable @State var accent = Color.purple
let palette: [Color] = [.purple, .blue, .teal, .green, .yellow, .orange,
.red, .pink, .indigo, .mint, .brown, .gray]
VStack(spacing: SK.Space.xl) {
SKColorSwatchPicker(selection: $accent, colors: palette)
RoundedRectangle(cornerRadius: SK.Radius.lg, style: .continuous)
.fill(accent)
.frame(height: 80)
.skAnimation(.settle, value: accent)
}
.padding(SK.Space.xl)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(SK.Palette.surfaceSunken)
}
Questions
- Is this SwiftUI color swatch picker free for commercial apps?
- Yes. Swift Kit UI is MIT licensed, so you can use it in personal and commercial apps with no payment or sign-up. Keep the licence notice with the code.
- What does it depend on?
- SKColorSwatchPicker.swift depends only on SwiftKitUI.swift, a single foundation file with the design tokens and motion curves. There are no third-party packages.
- Which iOS versions does it support?
- iOS 17 and later, plus macOS 14.
Related components
Building a whole app? The Swift Kit adds auth, payments and onboarding, ready to ship.