A SwiftUI color picker component library for macOS, designed to replace the default ColorPicker component. In addition, I’ve created another component library, Colorful, which offers a different user experience with a distinct style.
✦ My macOS/iOS application ✦
Welcome to download DevTutor, a cheat sheet app designed to help developers quickly build excellent applications using SwiftUI.
import ColorSelector
struct ContentView: View {
@State var color: Color? = .red
@State var colorClear: Color? = .clear
@State var nsColor: NSColor? = NSColor.red
var body: some View {
ColorSelector("Color", selection: $color)
ColorSelector(selection: $colorClear)
ColorSelector(nsColor: $nsColor, arrowEdge: .top)
ColorSelector(selection: $color) {
Text("Color Picker")
}
}
}
Using the swatchColors
environment value, developers can customize the color list in the color selector, replacing the default color options.
struct ContentView: View {
@State var color: Color? = .red
var body: some View {
ColorSelector(selection: $color)
.environment(\.swatchColors, [
NSColor(hue: 0.999, saturation: 0.857, brightness: 0.878, alpha: 1.0),
NSColor(hue: 0.066, saturation: 1.000, brightness: 0.980, alpha: 1.0),
NSColor(hue: 0.121, saturation: 0.976, brightness: 0.969, alpha: 1.0),
])
///
ColorSelector(selection: $colorClear, arrowEdge: .top)
}
}
By setting the cornerSize
(corner radius) and pointSize
(point size) environment values, the corner radius and point size can be dynamically adjusted.
struct ContentView: View {
@State var color: Color? = .red
@State var cornerRadius: CGFloat = 6
@State var pointSize: CGSize = .init(width: 12, height: 12)
var body: some View {
ColorSelector(selection: $color)
.environment(\.cornerSize, cornerRadius)
.environment(\.pointSize, pointSize)
}
}
arrowEdge: The edge of the attachmentAnchor that defines the location of the popover’s arrow. The default is nil, which results in the system allowing any arrow edge.
import ColorSelector
struct ContentView: View {
@State var colorClear: Color? = .clear
var body: some View {
ColorSelector(selection: $colorClear, arrowEdge: .bottom)
}
}
Use the showsAlpha
modifier to control the visibility of the alpha (opacity) slider in the picker panel.
import ColorSelector
struct ContentView: View {
@State var color: Color? = .clear
var body: some View {
ColorSelector(selection: $color)
.showsAlpha(false)
}
}
Customize button size using the controlSize
modifier
ColorSelector(selection: $color)
.controlSize(.regular)
The colorSelectorPopover
modifier provides an easy way to add color picker functionality to any view. The modifier attaches a popover that shows when triggered externally.
struct ContentView: View {
@State private var backgroundColor: Color? = .blue
@State private var showColorPicker = false
var body: some View {
Text("Background Color")
.padding()
.background(backgroundColor ?? .clear)
.onTapGesture {
showColorPicker = true
}
.colorSelectorPopover(
selection: $backgroundColor,
isPresented: $showColorPicker
)
}
}
Basic usage with external popover control:
@State private var textColor: Color? = .primary
@State private var showTextPicker = false
Button("Choose Text Color") {
showTextPicker = true
}
.colorSelectorPopover(
selection: $textColor,
isPresented: $showTextPicker,
showsAlpha: false
)
Using NSColor binding:
@State private var shadowColor: NSColor? = NSColor.gray
@State private var showShadowPicker = false
Text("Shadow Color")
.onTapGesture { showShadowPicker = true }
.colorSelectorPopover(
nsColor: $shadowColor,
isPresented: $showShadowPicker,
arrowEdge: .top
)
Available parameters:
selection
: A binding to the selected ColornsColor
: A binding to the selected NSColor (alternative to selection)isPresented
: A binding to control popover visibilityarrowEdge
: The edge where the popover arrow appears (default: system decides)showsAlpha
: Whether to show alpha controls (default: true)
The ColorSelectorButton
is a standalone button component that displays the current selected color and can trigger a popover when tapped. This component provides the visual color representation without the popover functionality built-in.
struct ContentView: View {
@State private var selectedColor: Color? = .blue
@State private var showColorPicker = false
@State private var buttonSize: ControlSize = .regular
var body: some View {
VStack(spacing: 20) {
// Color selector button
ColorSelectorButton(
popover: $showColorPicker,
selection: $selectedColor,
controlSize: $buttonSize
)
// Display current color
Text("Selected: \(selectedColor?.description ?? "None")")
}
.colorSelectorPopover(
selection: $selectedColor,
isPresented: $showColorPicker
)
}
}
Customize button size:
@State private var buttonSize: ControlSize = .large
ColorSelectorButton(
popover: $showColorPicker,
selection: $selectedColor,
controlSize: $buttonSize
)
Available control sizes: .mini
, .small
, .regular
, .large
, .extraLarge
struct ContentView: View {
@State var alpha: CGFloat = 1.0
var saturation: CGFloat = 1.0
var brightness: CGFloat = 1.0
var hue: CGFloat = 0.0
var body: some View {
AlphaSlider(
alpha: $alpha,
hue: hue,
saturation: saturation,
brightness: brightness
)
}
}
struct ContentView: View {
@State var color: Color = Color.red
var cornerRadius: CGFloat = 6
var pointSize: CGSize = .init(width: 8, height: 8)
var body: some View {
ColorSampler(
color: $color,
cornerRadius: cornerRadius,
pointSize: pointSize
)
}
}
You can customize the width and height of the rectangle using the rectSize
modifier.
#Preview {
@Previewable @State var color: Color? = Color.blue
ColorSampler(color: $color)
.rectSize(23)
}
struct ContentView: View {
@State var hue: CGFloat = 1
var body: some View {
HueSlider(hue: $hue)
}
}
struct ContentView: View {
@State var saturation: CGFloat = 1.0
@State var brightness: CGFloat = 1.0
var hue: CGFloat = 0.0
var body: some View {
Saturation(
saturation: $saturation,
brightness: $brightness,
hue: hue,
cornerRadius: 16
)
}
}
struct ContentView: View {
@State var color: NSColor = NSColor.white
var body: some View {
Swatch()
Swatch(nsColor: color) { value in
color = value
}
}
}
struct ContentView: View {
@State var saturation: CGFloat = 1.0
@State var brightness: CGFloat = 1.0
@State var hue: CGFloat = 0.0
@State var alpha: CGFloat = 1.0
var body: some View {
Sketch(
hue: $hue,
saturation: $saturation,
brightness: $brightness,
alpha: $alpha
)
.frame(width: 180, height: 230)
}
}
Licensed under the MIT License.