# .toOKLCH()

Read a color's lightness, chroma and hue the way the palette sees them, to compare or adjust it.

See a color the way the palette does with `toOKLCH()`: lightness, chroma and hue in OKLCH, the space every ramp is built in. It takes nothing and returns an `OKLCHColor` you can read, change and turn back into a `Color`:

```swift
let brandColor = Color(hex: "#00B386")
let oklch = brandColor.toOKLCH()   // OKLCHColor(l: 0.680, c: 0.139, h: 166.99)
oklch.h                            // 166.99, the hue ProTheme(hex:) builds the brand's theme on
```

Type any hex value to get it in every color type, with the Swift that makes it and the nearest palette stop:

A converter shows any hex color in every color type the library has, with the Swift initializer for each. #3C80C4 is `OKLCHColor(l: 0.5879, c: 0.1253, h: 250.8)`. [Try it on the live page](https://colortokenskit.com/api/to-oklch/).

## Choosing a color space

- OKLCH for how colors look: hue stays put as chroma changes, so the palette and the color functions use it.
- CIELab L\* for contrast: it depends only on luminance, as WCAG contrast does, so the palette holds it equal at each stop. [`.toLCH()`](https://colortokenskit.com/api/to-lch/index.md) and [`.toLAB()`](https://colortokenskit.com/api/to-lab/index.md) give it.
- RGB for handing colors to other code, with [`.toRGB()`](https://colortokenskit.com/api/to-rgb/index.md), and hex for colors inside sRGB, with [`.getHexString()`](https://colortokenskit.com/api/get-hex-string/index.md).

[Why OKLCH?](https://colortokenskit.com/under-the-hood/why-oklch/index.md) shows the difference.

## Making an OKLCHColor

```swift
OKLCHColor(l: 0.68, c: 0.14, h: 167)              // #00B386
OKLCHColor(hex: "#00B386")
OKLCHColor(oklchString: "oklch(0.68 0.14 167)")
```

Write `oklchString` with three plain numbers: no percent signs, no alpha, and `0.68` rather than `.68`. A string it can't read gives a default color, #E7729B, instead of an error. `OKLCHColor` matches CSS `oklch()` numbers to within rounding.

## Changing one value

`getColor(l:c:h:alpha:)` replaces the values you pass and returns a `Color`:

```swift
let oklch = Color(hex: "#00B386").toOKLCH()
let quieter = oklch.getColor(c: 0.05)   // same lightness and hue, closer to gray
```

It doesn't fit the result into Display P3 as the color functions do, so for more chroma, use [`saturate(by:)`](https://colortokenskit.com/api/saturate/index.md).

## The ramp at this hue

`_50` to `_1000`, `allStops` and `getColor(at:)` read the ramp of the color's own hue, and the static `getPrimaryColor(forHue:isGrayscale:)` gives a hue's `_450`. They return `OKLCHColor` values; for a theme with every token, use [`ProTheme(hex:)`](https://colortokenskit.com/api/protheme/index.md#from-a-hex-color) or [`ProTheme.primary(forHue:)`](https://colortokenskit.com/api/protheme/index.md#from-a-hue).

## How it behaves

Conversions between the CIELab and OK types pass through extended sRGB without clipping, so a Display P3 color comes through unchanged. A token has two values, and `toOKLCH()` reads one: on iOS 17, macOS 14 and later, the light-mode value. To read dark mode, convert the stop the token uses there.

Hues are stored wrapped to 0 to 360 and rounded to 0.01°, so `OKLCHColor(l: 0.5, c: 0.1, h: 370).h` is `10`. [`toColor()`](https://colortokenskit.com/api/to-color/index.md) and `getColor(l:c:h:alpha:)` always give an opaque color.

From an `OKLCHColor` you can go to `toRGB()`, `toLCH()`, `toOKLab()` and `toColor()`.

## API

```swift
public extension Color {
    func toOKLCH() -> OKLCHColor
}

public struct OKLCHColor: Hashable, Sendable {
    public let l: CGFloat       // 0 to 1
    public let c: CGFloat       // 0 to 0.32 inside sRGB, more in Display P3
    public let h: CGFloat       // 0 to 360
    public let alpha: CGFloat   // 0 to 1

    public init(l: CGFloat = 0, c: CGFloat = 0, h: CGFloat = 0, alpha: CGFloat = 1)
    public init(color: Color)
    public init(hex: String)
    public init(oklchString: String)

    public func getColor(
        l: CGFloat? = nil, c: CGFloat? = nil, h: CGFloat? = nil, alpha: CGFloat? = nil
    ) -> Color
    public func getColor(at index: Int) -> OKLCHColor
    public var allStops: [OKLCHColor] { get }
    public var _50: OKLCHColor { get }   // and every stop to _1000
    public static func getPrimaryColor(forHue hue: Double, isGrayscale: Bool = false) -> OKLCHColor
    public func lerp(_ other: OKLCHColor, t: CGFloat) -> OKLCHColor

    public func toRGB() -> RGBColor
    public func toLCH() -> LCHColor
    public func toOKLab() -> OKLabColor
    public func toColor() -> Color
}
```

`toOKLCH()` takes no parameters. `ProTheme` has it too, as in `brand._600.toOKLCH()`.

## Sources

- [Color+ColorSpaces.swift](https://github.com/metasidd/ColorTokensKit-Swift/blob/main/Sources/ColorTokensKit/Platform/SwiftUI/Color+ColorSpaces.swift), which defines `toOKLCH()` on `Color`.
- The [OKLCH](https://github.com/metasidd/ColorTokensKit-Swift/tree/main/Sources/ColorTokensKit/ColorSpace/OKLCH) folder, which defines `OKLCHColor`, its string parser and its stops.
- Björn Ottosson, [A perceptual color space for image processing](https://bottosson.github.io/posts/oklab/) (2020), which introduces OKLab and OKLCH.
- W3C, [CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/), which defines `oklch()`.

## See also

- [Why OKLCH?](https://colortokenskit.com/under-the-hood/why-oklch/index.md): Every hue looks evenly matched at each stop, so you can swap families without rechecking contrast.
- [.toOKLab()](https://colortokenskit.com/api/to-oklab/index.md): Get a color in OKLab, where straight-line math between colors looks even, for your own blends.
- [Color(hex:)](https://colortokenskit.com/api/color-hex/index.md): Turn a hex value from your design file into a SwiftUI color, with or without transparency.
- [ProTheme](https://colortokenskit.com/api/protheme/index.md): Make a theme from a hex, a hue or OKLCH numbers, and every stop and token keeps its contrast.
- [.normalizedHue and .rounded(to:)](https://colortokenskit.com/api/normalized-hue/index.md): Wrap any angle into 0° to 360° and round numbers the way the library stores every hue.

---

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