Skip to content
ColorTokensKitby Penguin Design Ventures
Contents
Function

Ready-made themes

37 themes to use as they are, from proPink to proRose, each with 20 stops and every token.

Updated View as Markdown

Pick a theme by name, such as Color.proBlue, and your view gets 20 stops and every token, in light and dark mode. There are 37 names: 36 hues, one every 10°, and proGray. Each is a ProTheme.

swift
let theme = Color.proBlue

Text("Lisbon")
    .font(.headline)
    .foregroundStyle(theme.foregroundPrimary)   // _1000 in light mode, _50 in dark
    .padding()
    .background(theme.backgroundSecondary)      // _100 in light mode, _800 in dark
light mode
Lisbon

Here are all 37, each from light to dark:

Giving a view a theme#

Pass the theme in and draw with its tokens. Then one name changes the whole view, and the contrast stays the same:

swift
struct TripCard: View {
    let theme: ProTheme

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text("Lisbon")
                .font(.headline)
                .foregroundStyle(theme.foregroundPrimary)
            Text("3 nights from October 12")
                .foregroundStyle(theme.foregroundSecondary)
        }
        .padding()
        .background(theme.backgroundSecondary)
    }
}

TripCard(theme: Color.proGold)
TripCard(theme: Color.proPink)
Color.proGold · light mode
Lisbon3 nights from October 12
Color.proPink · light mode
Lisbon3 nights from October 12

Letting people choose a theme#

Color.allProHues holds every theme by its name without the pro, so a setting can store a plain string:

swift
struct ThemeSetting: View {
    @AppStorage("theme") private var name = "Blue"

    var body: some View {
        Picker("Theme", selection: $name) {
            ForEach(Color.allProHues.keys.sorted(), id: \.self) { option in
                Text(option)
            }
        }
    }
}

let saved = UserDefaults.standard.string(forKey: "theme") ?? "Blue"
let theme = Color.allProHues[saved] ?? Color.proBlue

A dictionary has no order, so sort the names for a list. The fallback covers a name that's no longer there.

How it behaves#

Each name is ProTheme.primary(forHue:) at its hue: Color.proBlue is hue 250. Its own color is its _450 stop, and its tokens come from ColorTokens.swift.

Every hue has the same lightness and chroma at each stop, so swapping one name for another keeps your contrast. proGray has no hue and a lightness ladder of its own, and the tokens ColorTokens.swift puts on Color, such as Color.foregroundPrimary, are built on it.

Each name is a computed property, but the ramps behind it are built once and cached, so reading Color.proBlue in a view's body is cheap. ProTheme is Sendable, so you can pass themes between threads.

Older versions placed some names a few degrees off this grid, so after updating, a theme can look a little different. Troubleshooting lists what to check.

API#

swift
public extension Color {
    static var proGray: ProTheme { get }
    static var proPink: ProTheme { get }        // hue 0°, then one every 10°, to proRose at 350°
    static var allProHues: [String: ProTheme] { get }
}
HueThemeHueThemeHueTheme
0°proPink120°proChartreuse240°proAzure
10°proRuby130°proLime250°proBlue
20°proRed140°proGrass260°proCobalt
30°proTomato150°proGreen270°proIndigo
40°proCoral160°proJade280°proIris
50°proOrange170°proEmerald290°proViolet
60°proBrown180°proMint300°proGrape
70°proAmber190°proTeal310°proPurple
80°proGold200°proTurquoise320°proOrchid
90°proMustard210°proCyan330°proPlum
100°proYellow220°proCerulean340°proMagenta
110°proOlive230°proSky350°proRose

Each property returns a ProTheme whose own color is its _450 stop. allProHues maps each of the 37 names, such as "Blue" or "Gray", to the same value.

Sources#

See also

  • ProTheme Make a theme from a hex, a hue or OKLCH numbers, and every stop and token keeps its contrast.
  • Stops: ._50 to ._1000 Twenty fixed colors per theme, lightest to darkest, with the same contrast in every hue.
  • What does the library offer? 36 color themes, ready-to-use tokens with dark mode, a theme for your brand, and state functions.
  • Understanding semantic tokens Learn the 20 tokens by the job each one does, and get dark mode and passing contrast with them.