Skip to content
ColorTokensKitby Penguin Design Ventures
Contents
Function

.complement

Give a price or badge an accent that stands apart from your brand, at the same contrast.

Updated View as Markdown

Give the one thing that has to catch the eye, such as a price, an accent that stands apart from your brand with .complement. It turns your color or family halfway around the hue wheel and keeps its lightness, so the accent has the same contrast.

swift
let accent = brand.complement   // your brand's family, turned 180°

HStack(spacing: 16) {
    VStack(alignment: .leading, spacing: 4) {
        Text("Lisbon")
            .font(.headline)
            .foregroundStyle(brand.foregroundPrimary)
        Text("3 nights from October 12")
            .font(.subheadline)
            .foregroundStyle(brand.foregroundSecondary)
    }
    Text("€480")
        .padding(8)
        .foregroundStyle(accent.foregroundPrimary)   // _1000 in light mode, _50 in dark
        .background(accent.backgroundTertiary)       // _200 in light mode, _700 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
€480

Pick any color below, then set "See as" to "Lightness only": your color and its complement turn the same gray.

Try it / Harmonies
Color

Every OKLCH hue at this color's lightness

0°90°180°270°360°
light mode
#63a7fdproBlue._400
#da9630proAmber._400
dark mode
#63a7fdproBlue._400
#da9630proAmber._400
swift
let color = Color.proBlue._400.toColor()
color.complement

An accent from any token#

The Color version works on any color, tokens included, and keeps the token's job. The complement of a text token is a text color for both modes:

swift
Text("Sold out")
    .foregroundStyle(brand.foregroundTertiary.complement)   // _700 in light mode, _300 in dark, at 347°
light mode
Sold out

Complements of the built-in families#

The built-in families sit every 10° around the wheel, so the complement of one is another. Color.proBlue sits at 250°, and its complement is Color.proAmber, at 70°:

swift
let accent = Color.proBlue.complement   // Color.proAmber
#63a7fd
proBlue._400
#da9630
proAmber._400

How it behaves#

complement turns the hue with rotateHue(by: .degrees(180)). A palette color lands on the same stop of the opposite hue, so its contrast doesn't change. Any other color keeps its lightness and as much chroma as Display P3 can show at the new hue.

On a ProTheme, you get a whole family at the stop you started from, so every token works on it. Gray has no hue, so its complement is gray.

complement returns only the turned color. harmony(.complement) returns both, yours first. Only hue tells the two apart, so they match in grayscale; when color carries meaning, add a label. Color theory covers when an accent this strong is the right pick.

API#

swift
public extension Color {
    var complement: Color { get }
}

public extension ProTheme {
    var complement: ProTheme { get }
}

It takes no parameters. On Color, it returns the opposite hue at the same lightness, in both light and dark mode. On ProTheme, it returns the family on the opposite side of the wheel, at this color's stop.

Sources#

See also

  • .splitComplement(spread:) Two accents that stand apart from your brand, softer than its opposite, at the same contrast.
  • .triad Secondary and tertiary colors for tags and categories, at the same contrast as your brand.
  • .rotateHue(by:) Make an accent or a whole second theme from your brand color, at the same lightness.
  • Color theory Pair stops that always read, and pick secondary hues that match your brand, in both modes.