SwiftUI Colors – Exploring Overlooked Features

April 11th, 2025

⏱ Reading Time: 4 mins

Working with colors is one of the most common tasks for any developer in SwiftUI. However, we almost always stick to the basics; we apply the necessary colors and sometimes we also change their opacity. Occasionally we need to go deeper and use a combination of view modifiers or other techniques to manage a colorful visual outcome, ignoring that Color views have built-in capabilities that can often lead to similar results. So, in this post we'll see some not so well-known Color features; levels, gradients, mixing and shadows.


Presenting color of various levels

By default, the primary representation of a Color is what we use in SwiftUI. However, it's often necessary, to use variations of it, and before we resort to other techniques that alter the original color, there are built-in alternatives to consider first.

In fact, each Color object in SwiftUI has the following grades:

  • secondary
  • tertiary
  • quaternary

We access them by chaining to the original color. The following example fills a Rectangle shape and demonstrates that:

See that the additional levels become softer the deeper we get in light mode. The exact opposite happens in the dark mode though:

In Xcode, you'll also find the quinary level in addition to all the above, but it seems to have no difference to quaternary.

These levels make it extremely easy to get various grades of a color, but note something really important:

These are not Color objects but ShapeStyle values, and what they actually do is to affect how the color is presented. They may appear visually similar, but besides that, we cannot treat them like real colors; for instance, we cannot extract their Hex or RGB values.

Still, if the purpose is to just show or apply shades of a color, the above should be the first thing to try out.

Showing standard gradients

When it comes to gradients, types like the LinearGradient or RadialGradient are the first —and usually the only— candidates that come in mind in order to achieve the desired result. However, when the goal is to show a gradient based on shades of the same color, then there's a simpler way to do so. That is, to chain the gradient property to the color itself.

For instance:

The gradient property returns an AnyGradient instance, which can be used anywhere a ShapeStyle is accepted (such as in fillbackground, or foregroundStyle). But just as before, we can apply the secondary and the other style levels here too, and achieve gradients of various grades:

Mixing colors

As of iOS 18, it's more than straightforward to mix colors thanks to the mix(with:by:) instance method of the Color class. We can access this method through any color instance, and it returns a new color object composed by the mix of the first two.

The following code demonstrates how to mix the pink and yellow colors. The 0.65 value means that the second color —the with argument— contributes 65% to the new color, while the current one (pink in this case) contributes 35%. This combination results in a warm orange:

If necessary, we can chain multiple mix(with:by:) methods as shown next:

The above:

  • Blends 40% yellow with 60% pink.
  • Then blends 35% green with the first result.
  • Finally blends 50% blue with the second result.

Note that it's not mandatory to set hardcoded values as arguments to the by parameter. It's perfectly fine to use a property that changes dynamically inside the app.

Dropping shadows

Color values make it easy to apply a shadow without using the shadow modifier. There is the shadow(_:) instance method for that, which allows us to create either a drop or an inner shadow.

The arguments in both kinds of shadow are the same as those in the shadow modifier. Specifically, the only mandatory argument to provide is the radius value. Optionally, we can set a color, and offset values for either the horizontal or vertical axis, or both.

The following example demonstrates how to create a drop shadow, specifying the color, radius and vertical offset:

On the other hand, the following code creates an inner shadow:

Conclusion

As you see, there are color APIs that can speed up certain tasks that could be also done otherwise but with some more effort, so it'd be good to keep them in our tool belt for use whenever necessary. Displaying various levels of colors and basic gradients is a no-brainer, while color mixing is a great new feature as of iOS 18. And if you like depth, then applying shadow through color values is as easy as it gets. I hope you found this post useful. Thank you for reading.


Stay Up To Date

Subscribe to my newsletter and get notifiied instantly when I post something new on SerialCoder.dev.

    We respect your privacy. Unsubscribe at any time.