# Color(light:dark:)

Make any color switch between light and dark mode, the way every token does.

`Color(light:dark:)` makes one color that switches with light and dark mode, the way every token in `ColorTokens.swift` does. It takes a color for each mode, as SwiftUI `Color`s or `LCHColor`s, and returns a SwiftUI `Color` you can use anywhere.

```swift
extension Color {
    static var page: Color {
        Color(light: .white, dark: Color.proGray._900.toColor())   // softer than pure black
    }
}

Text("Lisbon")
    .padding()
    .foregroundStyle(Color.foregroundPrimary)
    .background(Color.page)
```

What this draws, with `Color`:

| Color               | light mode | dark mode |
| ------------------- | ---------- | --------- |
| `foregroundPrimary` | #000001    | #ffffff   |
| `white/gray._900`   | #ffffff    | #171718   |

## Adding a token to every theme

The built-in tokens are two stops each, joined by `Color(light:dark:)`. Add your own the same way, in an extension on `ProTheme`, and every theme gets it, your brand's included:

```swift
extension ProTheme {
    var badgeBackground: Color {
        Color(light: _200.toColor(), dark: _800.toColor())
    }
}

Text("New")
    .padding(8)
    .foregroundStyle(brand.foregroundPrimary)
    .background(brand.badgeBackground)
```

What this draws, with `#00B386`:

| Color               | light mode                            | dark mode                              |
| ------------------- | ------------------------------------- | -------------------------------------- |
| `foregroundPrimary` | color(display-p3 0.0176 0.1298 0.086) | #eaf8f2                                |
| `_200/_800`         | #9ce2c5                               | color(display-p3 0.0797 0.3134 0.2262) |

Defining a token is where `toColor()` belongs: it turns each [stop](https://colortokenskit.com/api/stops/index.md) into the `Color` this initializer takes. Views then draw with the token.

## UIKit and AppKit

`UIColor` and `NSColor` get the same initializer, for code that can't use a SwiftUI `Color`:

```swift
let page = UIColor(light: .white, dark: UIColor(Color.proGray._900.toColor()))
```

```swift
let page = NSColor(light: .white, dark: NSColor(Color.proGray._900.toColor()))
```

[ColorTokensKit in UIKit](https://colortokenskit.com/platforms/uikit/index.md) and [in AppKit](https://colortokenskit.com/platforms/appkit/index.md) show tokens built this way.

## From LCH values

A second version takes `LCHColor`s, for colors you already have as CIELab lightness, chroma and hue:

```swift
let tint = Color(light: LCHColor(l: 45, c: 40, h: 270), dark: LCHColor(l: 80, c: 30, h: 270))
```

## How it behaves

Underneath, it's a system color that picks a side each time it's drawn: a `UIColor` that reads the trait collection on iOS, tvOS and visionOS, and an `NSColor` that reads the appearance on macOS. So a view switches with the system setting, or with `.preferredColorScheme`, without being rebuilt. When the style is unspecified, UIKit gets the light color.

watchOS always draws in the dark appearance, so there it's simply the dark color.

It only knows light and dark. For a color that also changes with Increase Contrast, see [high contrast modes](https://colortokenskit.com/advanced/high-contrast/index.md).

You rarely need it for states. [`darken(by:)`](https://colortokenskit.com/api/darken/index.md), [`soften(by:)`](https://colortokenskit.com/api/soften/index.md) and the other color functions work out their result in each mode, so `brand.backgroundTertiary.darken()` already follows dark mode.

## API

```swift
public extension Color {
    init(light: @escaping @autoclosure () -> Color, dark: @escaping @autoclosure () -> Color)
    init(light: @escaping @autoclosure () -> LCHColor, dark: @escaping @autoclosure () -> LCHColor)
}

public extension UIColor {   // not on watchOS
    convenience init(light: @escaping @autoclosure () -> UIColor, dark: @escaping @autoclosure () -> UIColor)
}

public extension NSColor {
    convenience init(light: @escaping @autoclosure () -> NSColor, dark: @escaping @autoclosure () -> NSColor)
}
```

| Parameter | Type                                        | What it takes                                          |
| --------- | ------------------------------------------- | ------------------------------------------------------ |
| `light`   | `Color`, `LCHColor`, `UIColor` or `NSColor` | The color for light mode, and for an unspecified style |
| `dark`    | the same type as `light`                    | The color for dark mode, and the only color on watchOS |

Each returns a color of its own type that shows `light` or `dark` for the current appearance.

## Sources

- The library's [Color+Dynamic.swift](https://github.com/metasidd/ColorTokensKit-Swift/blob/main/Sources/ColorTokensKit/Platform/SwiftUI/Color+Dynamic.swift), [UIColor+Dynamic.swift](https://github.com/metasidd/ColorTokensKit-Swift/blob/main/Sources/ColorTokensKit/Platform/UIKit/UIColor+Dynamic.swift) and [NSColor+Dynamic.swift](https://github.com/metasidd/ColorTokensKit-Swift/blob/main/Sources/ColorTokensKit/Platform/AppKit/NSColor+Dynamic.swift).

## See also

- [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.
- [Stops: .\_50 to .\_1000](https://colortokenskit.com/api/stops/index.md): Twenty fixed colors per theme, lightest to darkest, with the same contrast in every hue.
- [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.
- [High contrast modes](https://colortokenskit.com/advanced/high-contrast/index.md): Respect Increase Contrast with one rule for every family: text and borders two stops stronger.
- [Using ColorTokensKit in UIKit](https://colortokenskit.com/platforms/uikit/index.md): Give UIKit views the palette's tokens as UIColors that follow dark mode on every iOS version tested.

---

From ColorTokensKit, by Penguin Design Ventures: https://colortokenskit.com/api/light-dark/ (updated September 26, 2026).
