We offer 36 color themes, plus gray, and everything you need to use them in your app: ready-to-use tokens that handle dark mode, a theme for your brand's own color, and functions for pressed and disabled states. Here are the themes, each from light to dark:
36 color themes of 20 stops#
let pink = Color.proPink // a theme, by name
pink._400 // one of its 20 stops, by number
pink.allStops.count // 20
Color.allProHues["Pink"] // the same theme, found by nameEach theme is a color family of 20 stops, from _50, nearly white, to _1000, nearly black: 740 colors in all. Pick a cell for its hex, hue and the Swift that makes it:
- 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()On this site, a stop's hex value is Display P3, the way an iPhone shows it. Many stops are beyond sRGB, and the library's getHexString() clamps those into sRGB, so in Swift, name the stop instead of copying its hex.
Ready-to-use tokens#
Every theme comes with 20 tokens, each named for its job in your interface. A token picks one stop for light mode and one for dark, so your app gets dark mode without picking a single dark color. Here are all 20 for proBlue:
- foregroundPrimaryPrimary text, selected iconsLisbonLisbon
- foregroundSecondarySecondary text, unselected iconsLisbonLisbon
- foregroundTertiaryTertiary text, disabled iconsLisbonLisbon
- invertedForegroundPrimaryPrimary text on inverted backgroundsLisbonLisbon
- invertedForegroundSecondarySecondary text on inverted backgroundsLisbonLisbon
- invertedForegroundTertiaryTertiary text on inverted backgroundsLisbonLisbon
- backgroundPrimaryMain content and app background
- backgroundSecondarySecondary backgrounds, cards
- backgroundTertiaryTertiary backgrounds, modals
- invertedBackgroundPrimaryMain background of inverted areas
- invertedBackgroundSecondaryCards on inverted areas
- invertedBackgroundTertiaryModals on inverted areas
- surfacePrimaryCards and sheets over other content
- surfaceSecondaryPanels and dialogs
- surfaceTertiaryTooltips and popovers
- invertedSurfacePrimaryCards and sheets on dark areas
- invertedSurfaceSecondaryPanels and dialogs on dark areas
- outlinePrimaryEdges people need to see, like fields and checkboxes
- outlineSecondaryDecorative borders and dividers
- outlineTertiaryDecorative hairlines and subtle borders
Semantic tokens lists the stops behind each one. ColorTokens.swift also puts the same names on Color, built on gray, for the parts of your app outside any theme.
A theme for your brand's color#
When your brand color isn't one of the 36 hues, make a theme from its hex:
let brand = ProTheme(hex: "#00B386")
VStack(alignment: .leading, spacing: 4) {
Text("Lisbon")
.font(.headline)
.foregroundStyle(brand.foregroundPrimary) // _1000 in light mode, _50 in dark
Text("3 nights from October 12")
.font(.subheadline)
.foregroundStyle(brand.foregroundSecondary) // _800 in light mode, _200 in dark
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(brand.backgroundPrimary) // _50 in light mode, _1000 in darkThe new theme sits between jade and emerald, keeps #00B386 as its own color, and has every stop and token the built-in themes have. Replacing your app colors shows how to move your colors over.
Functions for pressed and disabled 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 and _350
Text("Sold out").padding(12).background(fill.desaturate(by: 1)) // disabled: gray, as light as fill
}
.foregroundStyle(brand.invertedForegroundPrimary)Each state comes from the color you already have, so it's still a palette color and the label stays readable. Building for interaction states shows every state, and darken(by:) and desaturate(by:) explain the two functions.
Accessibility from day one#
Every hue has the same lightness at each stop, so a stop has the same contrast in every theme: _600 passes WCAG AA as text on white in all 36 hues, and every text token passes on its page background in both modes. In the chart above, set "See as" to "Lightness only", and each column of hues turns into one gray. How accessible is it? has the details.
See also
- How did we choose and build these colors? Why every hue shares one lightness and one chroma at each stop, and how the 36 hues were named.
- Understanding semantic tokens Learn the 20 tokens by the job each one does, and get dark mode and passing contrast with them.
- Setting up themes Recolor a view, a screen or your whole app from one value, with the same contrast in every hue.
- Installing ColorTokensKit Add one package and one file of tokens, and every view gets the palette and dark mode.