Storing Color in UserDefaults
- lioneldude
- Aug 31
- 2 min read
A color picker is a simple but powerful way to let users personalize your app. With just a few lines of SwiftUI code, you can allow them to choose their favorite colors. Since Color itself cannot be stored directly in UserDefaults, we convert it into a hex string and save it using @AppStorage.
UserDefaults is a natural fit here because it’s designed for lightweight user preferences — things like toggles, theme settings, or last-used values. It saves the data directly on the device’s local storage, which makes it fast and reliable without needing a database. However, UserDefaults only supports a limited set of data types (like Int, Bool, Double, String, or Data). That’s why converting a Color into a hex string is the simplest way to make it persist.
Why use a Color Picker?
Adding a color picker gives your users quick control over the theme, background, or highlight colors. It’s an easy way to make the app feel more personal and engaging.

Use a color picker by calling the ColorPicker() API, where:
structure ColorPicker<Label> where Label : ViewExample code:
// supportsOpacity is optional, defaults to true
ColorPicker("Select a Color", selection: $selectedColor, supportsOpacity: true)
.onChange(of: selectedColor) { _, newColor in
colorHex = newColor.hexString
}The ColorPicker displays the system’s native picker UI.
The selection is stored as a hex string in @AppStorage.
A helper extension handles conversion between Color and hex strings (shown below).
The onChange modifier is used to react to updates whenever the user picks a new color, so the stored hex string always stays in sync.
Extension for Color, remember to Import SwiftUI.
/// Extension to Color with helpers to convert from Color to hex string and back
extension Color {
// Convert SwiftUI Color into hex string format
var hexString: String {
let uiColor = UIColor(self)
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
// Get the components that form the color in the RGB color space
uiColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
// e.g. #FF0000FF
return String(format: "#%02X%02X%02X%02X",
lroundf(Float(red * 255)),
lroundf(Float(green * 255)),
lroundf(Float(blue * 255)),
lroundf(Float(alpha * 255))) // Include alpha component, opacity from 0 to 1
}
// Convert hex string into SwiftUI Color
init?(hex: String) {
var hexSanitized = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
hexSanitized = hexSanitized.replacingOccurrences(of: "#", with: "")
var rgb: UInt64 = 0
// Read the hex string and convert into a 64-bit unsigned integer
guard Scanner(string: hexSanitized).scanHexInt64(&rgb) else { return nil }
// Use bit masking and shifting to extract red, green, blue and alpha components
let red = Double((rgb & 0xFF000000) >> 24) / 255.0
let green = Double((rgb & 0x00FF0000) >> 16) / 255.0
let blue = Double((rgb & 0x0000FF00) >> 8) / 255.0
let alpha = Double(rgb & 0x000000FF) / 255.0
self.init(.sRGB, red: red, green: green, blue: blue, opacity: alpha)
}
}This way, the chosen color is saved in UserDefaults and automatically restored when the app relaunches.
See More
See the color picker in action in my stopwatch app: MyChronoPro Lap Tracker
Explore the demo project on GitHub: ColorPickerDemo



Comments