- OKLCH
- 0.639 0.15 250
- L* (CIELab)
- 58.2
- Family hue
- 250°
- vs white
- 3.37:1
- vs black
- 6.23:1
Color.proBlue._500.toColor()How it works#
Every hue becomes a ramp of 20 stops, and all 36 hues share one lightness at each stop. A token names a job, like secondary text, and picks one stop for light mode and one for dark. Your views use tokens, so they follow dark mode and any theme on their own. What are tokens? walks through it.
What you get#
A palette of well-defined colors#
We give you 37 families of 20 stops, the 740 colors at the top of this page. Every hue has the same lightness at each stop, so _600 means the same contrast in red as in blue. Many colors reach past sRGB into Display P3, the wider range of color an iPhone screen shows, and any hue you like, such as your brand's, can become a family of its own. What does the library offer? shows every stop.
Automatic dark mode#
let brand = ProTheme(hex: "#00B386")
HStack {
VStack(alignment: .leading, spacing: 4) {
Text("LIS → KIX")
.font(.headline)
.foregroundStyle(brand.foregroundPrimary) // _1000 in light mode, _50 in dark
Text("Oct 12 · 14h 20m")
.font(.subheadline)
.foregroundStyle(brand.foregroundSecondary) // _800 in light mode, _200 in dark
}
Spacer()
Text("€620")
.foregroundStyle(brand.foregroundPrimary)
}
.padding()
.background(brand.backgroundPrimary) // _50 in light mode, _1000 in darkA token names the job a color does and picks a stop for each mode. We give you 20 of them, tested in production, so you never write a dark-mode color by hand. What are tokens? explains how they work.
Built-in theming#
struct TripCard: View {
let city: String
let price: String
let theme: ProTheme
var body: some View {
HStack(spacing: 12) {
Image(systemName: "airplane")
.foregroundStyle(theme.foregroundSecondary)
.frame(width: 44, height: 44)
.background(theme.backgroundTertiary, in: .rect(cornerRadius: 12))
VStack(alignment: .leading, spacing: 2) {
Text(city)
.font(.headline)
.foregroundStyle(theme.foregroundPrimary)
Text("3 nights from October 12")
.font(.subheadline)
.foregroundStyle(theme.foregroundSecondary)
}
Spacer()
Text(price)
.font(.subheadline.weight(.semibold))
.foregroundStyle(theme.foregroundPrimary)
.padding(.horizontal, 10)
.padding(.vertical, 4)
.background(theme.backgroundPrimary, in: .capsule)
Image(systemName: "chevron.right")
.foregroundStyle(theme.foregroundTertiary)
}
.padding(12)
.background(theme.backgroundSecondary, in: .rect(cornerRadius: 16))
}
}
VStack(spacing: 10) {
TripCard(city: "Lisbon", price: "€420", theme: Color.proOrange)
TripCard(city: "Kyoto", price: "€980", theme: Color.proPink)
TripCard(city: "Reykjavík", price: "€640", theme: Color.proSky)
}Every family has the same tokens at the same contrast, so a view that takes a theme can wear any of them, in one line. Setting up themes shows how far that goes.
Accessibility from day one#
SwiftUI's system colors are tuned one at a time, so as text on white, none of the three above reaches the 4.5:1 that WCAG AA asks for body text. Ours share one lightness at each stop, so _600 passes in every hue. Every text token passes AA on the page background, in both modes, and for stops you pick yourself, 12 stops apart always reaches 4.5:1. How accessible is it? lists what's guaranteed, and why use ColorTokensKit over native colors? compares the two in full.
Functions for interaction states#
let fill = brand.invertedBackgroundTertiary // _650 in light mode, _250 in dark
HStack {
Text("Book now").padding(12).background(fill)
Text("Book now").padding(12).background(fill.darken(by: 2)) // pressed: _750 in light mode, _350 in dark
Text("Sold out").padding(12).background(fill.desaturate(by: 1)) // disabled: gray at the same lightness
}
.foregroundStyle(brand.invertedForegroundPrimary)Hover, pressed and disabled colors come from the color you already have, so you don't pick a new color for each state, and "Sold out" keeps the button's contrast. Building for interaction states shows every state, and darken(by:) and desaturate(by:) have the details.
Next steps
- What are tokens? Colors picked one at a time never line up. Tokens name each job and pick its color in both modes.
- Installing ColorTokensKit Add one package and one file of tokens, and every view gets the palette and dark mode.
- Using your first tokens Color text, buttons, cards and lists with tokens, then theme a movie card in one line.
- Components and examples Copy the common mobile components, from buttons to paywalls, each built from tokens for both modes.