# Using your first tokens

Color text, buttons, cards and lists with tokens, then theme a movie card in one line.

Color text, buttons, cards and lists by the job each color does, and each one follows light and dark mode on its own.

## Color text by importance

```swift
VStack(alignment: .leading, spacing: 4) {
    Text("Lisbon")
        .font(.headline)
        .foregroundStyle(Color.foregroundPrimary)     // _1000 in light mode, _50 in dark
    Text("3 nights from October 12")
        .font(.subheadline)
        .foregroundStyle(Color.foregroundSecondary)   // _800 in light mode, _200 in dark
    Text("Updated 2 min ago")
        .font(.footnote)
        .foregroundStyle(Color.foregroundTertiary)    // _700 in light mode, _300 in dark
}
```

What this draws, with `Color`:

| Color                 | light mode | dark mode |
| --------------------- | ---------- | --------- |
| `foregroundPrimary`   | #000001    | #ffffff   |
| `foregroundSecondary` | #2c2c2c    | #dddddd   |
| `foregroundTertiary`  | #454545    | #c0c0c0   |

> This assumes you've added the package and copied `ColorTokens.swift`. If you haven't, [set it up first](https://colortokenskit.com/getting-started/installing/index.md).

These are the gray tokens on `Color`. Even tertiary, the faintest, measures 9.55:1 or more against the page in both modes.

## Fill or outline a button

```swift
let brand = ProTheme(hex: "#00B386")

HStack {
    Button { } label: {
        Text("Book now")
            .padding(.vertical, 10)
            .padding(.horizontal, 16)
            .foregroundStyle(brand.invertedForegroundPrimary)   // _50 in light mode, _1000 in dark
            .background(brand.invertedBackgroundPrimary)        // _900 in light mode, _50 in dark
    }
    Button { } label: {
        Text("Details")
            .padding(.vertical, 10)
            .padding(.horizontal, 16)
            .foregroundStyle(brand.foregroundPrimary)
            .border(brand.outlinePrimary)                       // _600 in light mode, _350 in dark
    }
}
.buttonStyle(.plain)
```

What this draws, with `#00B386`:

| Color                       | light mode                             | dark mode                              |
| --------------------------- | -------------------------------------- | -------------------------------------- |
| `invertedForegroundPrimary` | #eaf8f2                                | color(display-p3 0.0176 0.1298 0.086)  |
| `invertedBackgroundPrimary` | color(display-p3 0.0474 0.2188 0.1544) | #eaf8f2                                |
| `foregroundPrimary`         | color(display-p3 0.0176 0.1298 0.086)  | #eaf8f2                                |
| `outlinePrimary`            | color(display-p3 0.1547 0.5182 0.3824) | color(display-p3 0.3144 0.7788 0.5953) |

For color, take the tokens from a family, here one [made from the brand's hex](https://colortokenskit.com/getting-started/replacing-colors/index.md#turn-your-brand-color-into-a-family). A filled button takes the inverted tokens. An outlined one takes `outlinePrimary`, which [clears 3:1 against the page](https://colortokenskit.com/advanced/color-theory/index.md#borders-people-need-to-see), so people can find the control's edge.

## Lay out a card

```swift
let theme = Color.proOrange   // Lisbon's color

VStack(alignment: .leading, spacing: 12) {
    VStack(alignment: .leading, spacing: 4) {
        Text("Lisbon")
            .font(.headline)
            .foregroundStyle(theme.foregroundPrimary)
        Text("3 nights from October 12")
            .font(.subheadline)
            .foregroundStyle(theme.foregroundSecondary)
    }
    HStack(spacing: 6) {
        ForEach(["Beach", "City"], id: \.self) { tag in
            Text(tag)
                .font(.caption)
                .padding(.vertical, 4)
                .padding(.horizontal, 8)
                .foregroundStyle(theme.foregroundPrimary)
                .background(theme.backgroundTertiary)   // _200 in light mode, _700 in dark
        }
    }
}
.padding()
.frame(maxWidth: .infinity, alignment: .leading)
.background(theme.backgroundPrimary)                    // _50 in light mode, _1000 in dark
```

What this draws, with `Color.proOrange`:

| Color                 | light mode                             | dark mode                              |
| --------------------- | -------------------------------------- | -------------------------------------- |
| `backgroundPrimary`   | color(display-p3 0.9936 0.9528 0.9271) | #301404                                |
| `foregroundPrimary`   | #301404                                | color(display-p3 0.9936 0.9528 0.9271) |
| `foregroundSecondary` | #6e3612                                | color(display-p3 0.978 0.79 0.6716)    |
| `backgroundTertiary`  | color(display-p3 0.978 0.79 0.6716)    | #90491a                                |

The card takes the page color, `backgroundPrimary`, and its tags sit a layer up on `backgroundTertiary`. Text on the tags takes `foregroundPrimary`, because `foregroundSecondary` drops to 4.48:1 there in dark mode.

## Build a list row

```swift
struct SettingRow: View {
    let title: String
    let value: String

    var body: some View {
        VStack(spacing: 0) {
            HStack {
                Text(title)
                    .foregroundStyle(Color.foregroundPrimary)
                Spacer()
                Text(value)
                    .foregroundStyle(Color.foregroundSecondary)
                Image(systemName: "chevron.right")
                    .foregroundStyle(Color.foregroundTertiary)
            }
            .padding()
            Rectangle()
                .fill(Color.outlineSecondary)   // _200 in light mode, _800 in dark
                .frame(height: 1)
        }
    }
}

VStack(spacing: 0) {
    SettingRow(title: "Price alerts", value: "On")
    SettingRow(title: "Home airport", value: "LIS")
}
```

What this draws, with `Color`:

| Color                 | light mode | dark mode |
| --------------------- | ---------- | --------- |
| `foregroundPrimary`   | #000001    | #ffffff   |
| `foregroundSecondary` | #2c2c2c    | #dddddd   |
| `foregroundTertiary`  | #454545    | #c0c0c0   |
| `outlineSecondary`    | #dddddd    | #2c2c2c   |

The label is primary, the value secondary and the chevron tertiary. The divider takes an outline token, which is faint on purpose.

## Build a movie card

```swift
struct MovieCard: View {
    let title: String
    let details: String
    let match: String
    let poster: String
    let theme: ProTheme

    var body: some View {
        HStack(alignment: .top, spacing: 14) {
            AsyncImage(url: URL(string: "https://picsum.photos/seed/\(poster)/300/450")) { image in
                image.resizable().scaledToFill()
            } placeholder: {
                theme.backgroundTertiary
            }
            .frame(width: 96, height: 144)
            .clipShape(.rect(cornerRadius: 16))

            VStack(alignment: .leading, spacing: 10) {
                Text(match)
                    .font(.caption.bold())
                    .padding(.vertical, 4)
                    .padding(.horizontal, 10)
                    .foregroundStyle(theme.foregroundPrimary)
                    .background(theme.backgroundTertiary, in: .capsule)
                VStack(alignment: .leading, spacing: 2) {
                    Text(title)
                        .font(.title3.bold())
                        .foregroundStyle(theme.foregroundPrimary)
                    Text(details)
                        .font(.subheadline)
                        .foregroundStyle(theme.foregroundSecondary)
                }
                Label("Watch trailer", systemImage: "play.fill")
                    .font(.subheadline.bold())
                    .padding(.vertical, 8)
                    .padding(.horizontal, 14)
                    .foregroundStyle(theme.invertedForegroundPrimary)
                    .background(theme.invertedBackgroundTertiary, in: .capsule)
            }
            Spacer(minLength: 0)
        }
        .padding(12)
        .background(
            [theme.surfaceTertiary, theme.surfacePrimary].proGradient(),
            in: .rect(cornerRadius: 28)
        )
        .overlay(RoundedRectangle(cornerRadius: 28).strokeBorder(theme.outlineTertiary))
    }
}

MovieCard(
    title: "Sintra Summer", details: "2024 · 1h 48m · Romance",
    match: "🍿 92% match", poster: "sintra", theme: Color.proRose
)
```

What this draws, with `Color.proRose`:

| Color                        | light mode                                   | dark mode                              |
| ---------------------------- | -------------------------------------------- | -------------------------------------- |
| `surfaceTertiary`            | color(display-p3 0.9716 0.7706 0.8686 / 0.1) | rgb(142 67 105 / 0.1)                  |
| `surfacePrimary`             | color(display-p3 0.9716 0.7706 0.8686 / 0.5) | rgb(142 67 105 / 0.5)                  |
| `outlineTertiary`            | color(display-p3 0.9857 0.8915 0.9356)       | #4d2138                                |
| `foregroundPrimary`          | #2f1221                                      | #fff1f7                                |
| `backgroundTertiary`         | color(display-p3 0.9716 0.7706 0.8686)       | #8e4369                                |
| `foregroundSecondary`        | #6c3250                                      | color(display-p3 0.9716 0.7706 0.8686) |
| `invertedBackgroundTertiary` | #9f4c76                                      | color(display-p3 0.9658 0.7035 0.8346) |
| `invertedForegroundPrimary`  | #fff1f7                                      | #2f1221                                |

It draws a linear gradient from `surfaceTertiary` to `surfacePrimary`, with `.vivid` and `.smooth`.

A movie app could show a card like this for each recommendation, and every color in it comes from one theme. The match pill sits on `backgroundTertiary`, the trailer button uses the inverted tokens, and the wash is a [gradient](https://colortokenskit.com/advanced/gradient-theory/index.md) between two translucent surface tokens. The details keep 7.4:1 or more even where the wash is strongest, in every hue. The poster's corners are the card's radius minus its padding, so the two curves stay parallel.

## Theme it in one line

Pass each movie a theme that suits its mood, and nothing else changes:

```swift
VStack(spacing: 12) {
    MovieCard(
        title: "Night Train to Porto", details: "2023 · 2h 4m · Thriller",
        match: "🍿 88% match", poster: "porto", theme: Color.proIndigo
    )
    MovieCard(
        title: "The Lisbon Bakery", details: "2025 · 1h 31m · Comedy",
        match: "🍿 95% match", poster: "bakery", theme: Color.proAmber
    )
}
```

What this draws:

| Color                               | light mode                                   | dark mode                                   |
| ----------------------------------- | -------------------------------------------- | ------------------------------------------- |
| `indigo.surfaceTertiary`            | color(display-p3 0.7757 0.8257 0.9966 / 0.1) | rgb(69 89 157 / 0.1)                        |
| `indigo.surfacePrimary`             | color(display-p3 0.7757 0.8257 0.9966 / 0.5) | rgb(69 89 157 / 0.5)                        |
| `indigo.outlineTertiary`            | color(display-p3 0.8913 0.9164 0.9984)       | #232e55                                     |
| `indigo.backgroundTertiary`         | color(display-p3 0.7757 0.8257 0.9966)       | #45599d                                     |
| `indigo.foregroundPrimary`          | #131a35                                      | color(display-p3 0.9477 0.9599 0.9992)      |
| `indigo.foregroundSecondary`        | #344378                                      | color(display-p3 0.7757 0.8257 0.9966)      |
| `indigo.invertedBackgroundTertiary` | #4f64af                                      | color(display-p3 0.7152 0.7771 0.9957)      |
| `indigo.invertedForegroundPrimary`  | color(display-p3 0.9477 0.9599 0.9992)       | #131a35                                     |
| `amber.surfaceTertiary`             | rgb(248 204 155 / 0.1)                       | color(display-p3 0.4939 0.325 0.0599 / 0.1) |
| `amber.surfacePrimary`              | rgb(248 204 155 / 0.5)                       | color(display-p3 0.4939 0.325 0.0599 / 0.5) |
| `amber.outlineTertiary`             | #fbe7d1                                      | color(display-p3 0.2647 0.1673 0.0203)      |
| `amber.backgroundTertiary`          | #f8cc9b                                      | color(display-p3 0.4939 0.325 0.0599)       |
| `amber.foregroundPrimary`           | color(display-p3 0.1611 0.0948 0.007)        | #fdf4e9                                     |
| `amber.foregroundSecondary`         | color(display-p3 0.3758 0.2436 0.0371)       | #f8cc9b                                     |
| `amber.invertedBackgroundTertiary`  | color(display-p3 0.5534 0.3671 0.0771)       | #f7be7a                                     |
| `amber.invertedForegroundPrimary`   | #fdf4e9                                      | color(display-p3 0.1611 0.0948 0.007)       |

It draws a linear gradient from `indigo.surfaceTertiary` to `indigo.surfacePrimary`, with `.vivid` and `.smooth`; a linear gradient from `amber.surfaceTertiary` to `amber.surfacePrimary`, with `.vivid` and `.smooth`.

Every family has the same lightness at each stop, so the text keeps its contrast in every theme. [Setting up themes](https://colortokenskit.com/advanced/themes/index.md) takes this to a whole screen.

## Next steps

- [Replacing your app colors](https://colortokenskit.com/getting-started/replacing-colors/index.md): Move backgrounds, text, outlines, states, gradients and charts to tokens, one screen at a time.
- [Building for interaction states](https://colortokenskit.com/getting-started/interaction-states/index.md): Give buttons and rows hover, pressed, selected and disabled colors that stay readable in both modes.
- [Managing dark mode](https://colortokenskit.com/getting-started/dark-mode/index.md): Get dark mode without extra code: tokens switch stops for you, and your own colors can too.
- [Understanding semantic tokens](https://colortokenskit.com/getting-started/semantic-tokens/index.md): Learn the 20 tokens by the job each one does, and get dark mode and passing contrast with them.
- [Components and examples](https://colortokenskit.com/getting-started/components/index.md): Copy the common mobile components, from buttons to paywalls, each built from tokens for both modes.

---

From ColorTokensKit, by Penguin Design Ventures: https://colortokenskit.com/getting-started/first-tokens/ (updated September 26, 2026).
