Learn how to apply monochrome, hierarchical, palette, and multicolor rendering modes to SF Symbols, plus variable color for status indicators, in SwiftUI.
SF Symbols support four rendering modes, and choosing the right one transforms how an icon reads. The modes are monochrome, hierarchical, palette, and multicolor.
Monochrome paints the whole symbol in one color. Hierarchical uses one color but varies opacity across layers to suggest depth.
Palette lets you assign different colors to different layers of a symbol. Multicolor uses the colors Apple baked into the symbol, like a yellow-and-blue weather glyph.
Understanding which mode fits a given symbol is the key skill. Not every symbol has the layers needed for hierarchical or palette to look distinct.
Monochrome is the default and the safest choice for most UI. You tint it with `foregroundStyle`.
Image(systemName: "trash")
.foregroundStyle(.red)
This is exactly right for toolbar buttons, list accessories, and anywhere you want a clean single-color icon. It guarantees legibility.
Monochrome also adapts naturally to light and dark mode when you use semantic colors like `.primary` or `.secondary`. Prefer those over hard-coded colors for system-feeling UI.
When in doubt, default to monochrome. The fancier modes are tools for specific moments, not a baseline.
Hierarchical mode keeps a single hue but introduces opacity tiers, giving the symbol a sense of layering. You opt in with `symbolRenderingMode`.
Image(systemName: "square.stack.3d.up")
.symbolRenderingMode(.hierarchical)
.foregroundStyle(.indigo)
This shines on symbols with overlapping or stacked elements, where the opacity steps clarify structure. It reads as more refined than flat monochrome.
Because it uses one color, hierarchical stays tasteful and on-brand. You get visual richness without a rainbow of colors competing for attention.
Preview the symbol in the SF Symbols app to confirm it has multiple layers. On a flat symbol, hierarchical looks nearly identical to monochrome.
Palette mode gives you explicit control by mapping colors to a symbol's layers. You pass multiple styles to `foregroundStyle`.
Image(systemName: "person.crop.circle.badge.plus")
.symbolRenderingMode(.palette)
.foregroundStyle(.white, .green)
The order of colors corresponds to the symbol's layer order. The first color hits the primary layer, the second the next layer, and so on.
Palette is powerful for badges and status glyphs where you want, say, a neutral base with a colored accent. It makes the meaningful part pop.
Know the layer count before you choose colors. If you supply fewer colors than layers, remaining layers reuse the last color you provided.
Multicolor mode tells the system to use the colors the symbol ships with. Weather, media, and many object symbols include intentional color.
Image(systemName: "cloud.sun.rain.fill")
.symbolRenderingMode(.multicolor)
This is the right call when a symbol's meaning depends on its colors, like a yellow sun or a red battery warning. Overriding those colors would erase intent.
Multicolor requires no color arguments from you. The symbol supplies its own palette.
Use it selectively. A screen full of multicolor symbols can feel busy, so reserve it for symbols where color carries information.
Variable color is separate from rendering mode and answers a different question: how full or active is this symbol? You supply a value from 0 to 1.
Image(systemName: "cellularbars", variableValue: signalStrength)
The symbol fills its variable layers in proportion to that value, which suits signal, volume, and progress. As `signalStrength` changes, the fill changes.
This works only on symbols that include variable color layers, which the SF Symbols app clearly marks. On other symbols the value is ignored.
You can combine variable color with a rendering mode and a tint, layering several capabilities into one expressive icon.
Rendering modes stack with the weight and scale controls you already use. A hierarchical symbol can still be semibold and large.
Image(systemName: "bell.badge")
.symbolRenderingMode(.hierarchical)
.font(.title2.weight(.semibold))
.foregroundStyle(.orange)
This composability is the whole point of the system. You tune meaning through color and presence through weight and scale independently.
Keep the surrounding text in mind. Match weight to nearby labels so the icon feels integrated rather than bolted on.
Prototype combinations in the SF Symbols app before coding. Seeing the result first saves build-and-run cycles.
Always verify your color choices in both light and dark appearances. A palette that looks great on white can vanish on black.
Prefer semantic colors and system tints where possible, since they adapt automatically. Hard-coded colors are a common source of dark mode contrast bugs.
Check contrast for symbols that carry meaning, especially status indicators. Users with low vision must be able to distinguish states.
Remember accessibility settings like increased contrast and reduced transparency can affect how hierarchical opacity reads, so test with those enabled.
Default to monochrome for general UI, and reach for hierarchical when a layered symbol benefits from subtle depth in a single color.
Use palette when you need deliberate, multi-color emphasis, and multicolor when the symbol's own colors carry meaning. Use variable color for anything that represents a level or progress.
The limitation to keep in mind is that modes depend on a symbol's internal layers. A flat symbol simply will not benefit from hierarchical or palette.
And as always, SF Symbols handle iconography only. The rest of shipping an iOS app still runs through Xcode, signing, and App Store submission.
Each rendering mode treats your tint color differently, and understanding that saves confusion. Monochrome uses your single tint for the whole symbol.
Hierarchical uses your tint as the base color and derives the lighter tiers from it by reducing opacity. Palette uses the colors you explicitly pass, in layer order.
Multicolor largely ignores your tint for the colored layers, since it uses the symbol's own palette. If a tint seems to have no effect, you are probably in multicolor mode.
Knowing which mode consumes your color and how lets you predict the result before you build and run. When in doubt, force monochrome to confirm the symbol can be colored at all, then layer complexity back in.
Mapping modes to common UI elements removes a lot of guesswork. Toolbar and navigation bar icons almost always want plain monochrome, tinted with a single accent color for a clean, system-consistent look.
List row accessories and small inline glyphs also read best in monochrome, since fine color detail is lost at small sizes anyway.
Larger, more prominent symbols, like an empty-state illustration or a settings header icon, are where hierarchical and palette earn their keep. At that size, the extra depth or color is visible and adds polish.
Status elements, such as a connectivity meter or a battery indicator, are the natural home for variable color. Reserve multicolor for symbols whose meaning genuinely depends on their built-in colors, like weather glyphs, and avoid scattering it across general UI where it just adds visual noise.
Hierarchical uses a single color with varying opacity across layers, while palette lets you assign distinct colors to each layer for explicit multi-color control.
That symbol likely has only one layer. Hierarchical needs multiple layers to show opacity tiers; check the symbol in the SF Symbols app.
Use the variable value initializer, for example Image(systemName: "cellularbars", variableValue: 0.6), on a symbol that supports variable color.
Yes. Rendering mode, variable color, font weight, and image scale all compose, so you can tune color and presence independently.
Monochrome. It is the safest, most legible default; use the other modes for specific cases where color or depth adds meaning.