Skip to content
ColorTokensKitby Penguin Design Ventures
Contents
Overview

What does the library offer?

36 color themes, ready-to-use tokens with dark mode, a theme for your brand, and state functions.

Updated View as Markdown

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#

swift
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 name

Each 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:

Palette / All 37 families × 20 stops
50
100
150
200
250
300
350
400
450
500
550
600
650
700
750
800
850
900
950
1000
proGray
proPink
proRuby
proRed
proTomato
proCoral
proOrange
proBrown
proAmber
proGold
proMustard
proYellow
proOlive
proChartreuse
proLime
proGrass
proGreen
proJade
proEmerald
proMint
proTeal
proTurquoise
proCyan
proCerulean
proSky
proAzure
proBlue
proCobalt
proIndigo
proIris
proViolet
proGrape
proPurple
proOrchid
proPlum
proMagenta
proRose
proBlue._500#508edc
OKLCH
0.639 0.15 250
L* (CIELab)
58.2
Family hue
250°
vs white
3.37:1
vs black
6.23:1
swift
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:

Foreground · Text and iconslightdark
  • 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
Background · Solid areas under textlightdark
  • backgroundPrimaryMain content and app background
  • backgroundSecondarySecondary backgrounds, cards
  • backgroundTertiaryTertiary backgrounds, modals
  • invertedBackgroundPrimaryMain background of inverted areas
  • invertedBackgroundSecondaryCards on inverted areas
  • invertedBackgroundTertiaryModals on inverted areas
Surface · See-through layerslightdark
  • surfacePrimaryCards and sheets over other content
  • surfaceSecondaryPanels and dialogs
  • surfaceTertiaryTooltips and popovers
  • invertedSurfacePrimaryCards and sheets on dark areas
  • invertedSurfaceSecondaryPanels and dialogs on dark areas
Outline · Borders and dividerslightdark
  • 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:

#00B386
swift
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 dark
light mode
Lisbon3 nights from October 12

The 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#

swift
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)
light mode
Book nowBook nowSold out

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#

Lisbon
proRed._600
Lisbon
proGreen._600
Lisbon
proBlue._600

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