# .soften(by:)

Make quieter text and fills from any token: lighter in light mode, darker in dark mode.

Make quieter text, icons and fills from any token with `soften(by:)`. It moves the color toward the page by whole stops, lighter in light mode and darker in dark mode, and returns a `Color`:

```swift
VStack(alignment: .leading, spacing: 4) {
    Text("Lisbon")
        .font(.headline)
        .foregroundStyle(brand.foregroundPrimary)
    Text("3 nights from October 12")
        .font(.subheadline)
        .foregroundStyle(brand.foregroundSecondary)                 // _800 in light, _200 in dark
    Text("Prices checked 2 min ago")
        .font(.footnote)
        .foregroundStyle(brand.foregroundSecondary.soften(by: 2))   // _700 in light, _300 in dark
}
```

What this draws, with `#00B386`:

| Color                 | light mode                             | dark mode |
| --------------------- | -------------------------------------- | --------- |
| `foregroundPrimary`   | color(display-p3 0.0176 0.1298 0.086)  | #eaf8f2   |
| `foregroundSecondary` | color(display-p3 0.0797 0.3134 0.2262) | #9ce2c5   |
| `_700/_300`           | color(display-p3 0.1149 0.4143 0.3028) | #4cd2a5   |

Two stops toward the page, `foregroundSecondary` lands on the stops of `foregroundTertiary`, so the footnote still passes WCAG AA on the page in both modes. Pick a color and a number of stops below:

A playground applies `soften()` to a palette stop, a token or a hex color. By default it shows `Color.proBlue._600.toColor().soften()`, which gives #4882ca in light mode and #3a69a5 in dark mode. [Try it on the live page](https://colortokenskit.com/api/soften/).

With the defaults, `proBlue._600` softens to `proBlue._550` in light mode and `proBlue._650` in dark.

## Quieter fills

A fill softens toward the page too. Here the tag you haven't picked sits one stop closer to the page than the one you have:

```swift
HStack {
    Text("Beach").padding(8).background(brand.backgroundTertiary)           // _200 and _700
    Text("City").padding(8).background(brand.backgroundTertiary.soften())   // _150 and _750
}
.font(.subheadline)
.foregroundStyle(brand.foregroundPrimary)
```

What this draws, with `#00B386`:

| Color                | light mode                            | dark mode                              |
| -------------------- | ------------------------------------- | -------------------------------------- |
| `foregroundPrimary`  | color(display-p3 0.0176 0.1298 0.086) | #eaf8f2                                |
| `backgroundTertiary` | #9ce2c5                               | color(display-p3 0.1149 0.4143 0.3028) |
| `_150/_750`          | #b9ead5                               | color(display-p3 0.0977 0.3637 0.2645) |

## Why not lighten()?

[`lighten(by:)`](https://colortokenskit.com/api/lighten/index.md) goes lighter in both modes, so lighter text is quieter on a white page and louder on a black one. `soften(by:)` picks the direction from the mode, so it's quieter in both.

## How it behaves

The direction comes from the appearance, not from what's behind the color. On an inverted surface, such as a dark banner in light mode, softening still goes lighter, which makes text on it louder. Use [`strengthen(by:)`](https://colortokenskit.com/api/strengthen/index.md) there, or the `invertedForeground` tokens. On watchOS, which always draws dark, softening always goes darker.

A palette color lands on an exact stop of its family, and stops at `_50` or `_1000`. A color off the palette moves by the same step in lightness and keeps its hue. The result keeps the color's opacity.

## API

```swift
public extension Color {
    func soften(by stops: Int = 1) -> Color
}
```

| Parameter | Type  | Default | What other values do                                                              |
| --------- | ----- | ------- | --------------------------------------------------------------------------------- |
| `stops`   | `Int` | `1`     | A negative value moves away from the page, so `soften(by: -1)` is `strengthen()`. |

It returns a new `Color` that resolves in each appearance: lighter in light mode and darker in dark mode.

## Sources

- [Color+Adjustments.swift](https://github.com/metasidd/ColorTokensKit-Swift/blob/main/Sources/ColorTokensKit/Adjustments/Color+Adjustments.swift), which defines `soften(by:)` and picks the direction from the color scheme.
- [ColorAdjustment.swift](https://github.com/metasidd/ColorTokensKit-Swift/blob/main/Sources/ColorTokensKit/Adjustments/ColorAdjustment.swift), which moves a color along the stops.

## See also

- [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.
- [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.
- [.darken(by:)](https://colortokenskit.com/api/darken/index.md): Make hover and pressed fills from any color, an exact stop darker 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.

---

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