SwiftUI Snippets

Mastering SF Symbols Rendering Modes in SwiftUI

November 23, 2025
5 min read
Featured image for blog post: Mastering SF Symbols Rendering Modes in SwiftUI

Mastering SF Symbols Rendering Modes in SwiftUI

I love SF Symbols so much I hardly even bother with anything else at this point. I understand that cross platform development expects different iconology and different libraries but I just don't care anymore. SF Symbols looks the cleanest, achieves non-verbal communication in an unbeatable way, and offers the most flexibility for customization. The others don't even close. At this point I know the library I want to use, and I copy the svgs from the SF Symbols library with paths colored properly, pick my size and boom we are done. Decision made in less than a second.

Let me show you some of the flexibility which makes it so good.

The Three Rendering Modes

SF Symbols in SwiftUI support three distinct rendering modes:

  1. Multicolor - Uses Apple's built-in color schemes
  2. Palette - Custom multi-layer coloring
  3. Monochrome - Single color rendering

Each mode serves a specific purpose and knowing when to use them will level up your SwiftUI UI game.

Multicolor: The Easy Win

For most weather icons, multicolor mode is perfect. Apple has already designed beautiful color schemes that look great out of the box:

Image(systemName: "cloud.sun.fill")
    .symbolRenderingMode(.multicolor)
    .font(.system(size: 32))

This gives you:

  • Sun icons in yellow/orange
  • Rain with blue water and gray clouds
  • Snow with appropriate blue/white coloring
  • And many more pre-designed combinations

The multicolor mode is Apple's gift to developers who want beautiful icons without the design work.

Palette: Custom Layer Control

Sometimes you need more control. The thunderstorm icon (cloud.bolt.fill) in multicolor mode doesn't quite pop the way we want. This is where palette mode shines:

Image(systemName: "cloud.bolt.fill")
    .symbolRenderingMode(.palette)
    .foregroundStyle(
        .white.opacity(0.9),  // Cloud layer
        Color(hex: "FDB813")   // Bolt layer
    )

Palette mode lets you control each layer of the symbol independently. For cloud.bolt.fill:

  • First color = cloud
  • Second color = bolt

This gives us a white cloud with a bright yellow lightning bolt that really stands out.

Monochrome: Keep It Simple

For some icons, a single solid color is exactly what you need. The snow icon works beautifully as pure white:

Image(systemName: "snow")
    .foregroundColor(.white)

Clean, simple, effective.

Putting It All Together

Here's how I structured the weather icon rendering logic in Border Times:

@ViewBuilder
private var weatherIconImage: some View {
    switch weather.condition {
    case .thunderstorm:
        // Use palette mode for custom colors
        Image(systemName: weather.condition.sfSymbol)
            .symbolRenderingMode(.palette)
            .foregroundStyle(
                .white.opacity(0.9),
                Color(hex: "FDB813")
            )

    case .snow:
        // Use solid white
        Image(systemName: weather.condition.sfSymbol)
            .foregroundColor(.white)

    default:
        // Use SF Symbols' built-in multicolor
        Image(systemName: weather.condition.sfSymbol)
            .symbolRenderingMode(.multicolor)
    }
}

This approach gives us:

  • Maximum flexibility - Each icon can be customized as needed
  • Clean code - @ViewBuilder with a switch keeps it readable
  • Beautiful defaults - Multicolor mode for most cases
  • Custom control - Palette and monochrome when we need them

The Complete Weather Card

The full implementation includes matching gradient backgrounds for each weather condition. The key is ensuring your background provides proper contrast for your icon choice:

struct WeatherCardView: View {
    let weather: WeatherData

    var body: some View {
        VStack(spacing: 4) {
            conditionText
            weatherIcon
            temperatureText
        }
        .background(weather.condition.gradient)
        .cornerRadius(12)
        .shadow(color: .black.opacity(0.15), radius: 10, x: 0, y: 5)
    }

    private var weatherIcon: some View {
        weatherIconImage
            .font(.system(size: 32))
            .shadow(color: .black.opacity(0.15), radius: 6, x: 0, y: 2)
    }

    // ... weatherIconImage implementation above
}

Pack Icon Logic Into Your Model

Here's where things get really clean: instead of scattering SF Symbol names and gradients throughout your views, pack everything into your model layer. This makes your view code trivial and your icon logic reusable.

enum WeatherCondition: String, Codable {
    case clear, partlyCloudy, cloudy, rain, thunderstorm, snow
    // ... other cases

    var sfSymbol: String {
        switch self {
        case .clear: return "sun.max.fill"
        case .partlyCloudy: return "cloud.sun.fill"
        case .rain: return "cloud.rain.fill"
        case .thunderstorm: return "cloud.bolt.fill"
        case .snow: return "snow"
        // ... other cases
        }
    }

    var gradient: LinearGradient {
        switch self {
        case .clear:
            return LinearGradient(
                colors: [Color(hex: "E8A906"), Color(hex: "F4B71C")],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            )
        case .rain:
            return LinearGradient(
                colors: [Color(hex: "4A90E2"), Color(hex: "6BA4E8")],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            )
        // ... other cases
        }
    }
}

Now your view code becomes ridiculously simple:

Image(systemName: weather.condition.sfSymbol)
    .symbolRenderingMode(.multicolor)

// And backgrounds:
.background(weather.condition.gradient)

No magic strings scattered around. No repeated color definitions. Just clean, centralized logic that makes your entire codebase easier to maintain.

Try It Yourself

The full code is in production at Border Times - check out the weather cards in the details section per crossing section. You can see all 11 weather conditions rendered with these techniques. If you're interested in full code snippets reach out at support@border-times.com.

SF Symbols are incredibly powerful when you understand all three rendering modes. Don't settle for monochrome when multicolor and palette modes can make your icons pop.

Happy coding!


Want to see more SwiftUI tips? Check out my other posts on collapsible indicators, pulsing live indicators, and status trackers.