BS
BleepingSwift
Published on

> Using SF Symbols in SwiftUI

Authors
  • avatar
    Name
    Mick MacCallum
    Twitter
    @0x7fs

SF Symbols is Apple's library of over 5,000 vector icons designed to integrate seamlessly with San Francisco, the system font. They scale automatically with Dynamic Type, support multiple weights and rendering modes, and are available across all Apple platforms.

Basic Usage

Display an SF Symbol using Image(systemName:):

Image(systemName: "star.fill")

The symbol renders at a size that matches nearby text. To use it in a button or label:

Button {
    // Action
} label: {
    Label("Favorites", systemImage: "star.fill")
}

The Label view pairs text with an icon, automatically handling layout and accessibility.

Sizing Symbols

SF Symbols scale with font size. The easiest way to resize them is with the .font() modifier:

Image(systemName: "heart.fill")
    .font(.largeTitle)

Image(systemName: "heart.fill")
    .font(.system(size: 50))

For relative sizing within the current context, use .imageScale():

HStack {
    Image(systemName: "star.fill")
        .imageScale(.small)

    Image(systemName: "star.fill")
        .imageScale(.medium)

    Image(systemName: "star.fill")
        .imageScale(.large)
}

If you need pixel-precise control, make the symbol resizable:

Image(systemName: "star.fill")
    .resizable()
    .frame(width: 44, height: 44)

Coloring Symbols

Apply colors using .foregroundStyle():

Image(systemName: "heart.fill")
    .foregroundStyle(.red)

Many symbols support multiple colors through hierarchical or palette rendering:

// Hierarchical - automatic opacity levels
Image(systemName: "square.stack.3d.up.fill")
    .symbolRenderingMode(.hierarchical)
    .foregroundStyle(.blue)

// Palette - explicit colors for each layer
Image(systemName: "person.crop.circle.badge.plus")
    .symbolRenderingMode(.palette)
    .foregroundStyle(.blue, .green)

Some symbols have built-in multicolor variants:

Image(systemName: "cloud.sun.rain.fill")
    .symbolRenderingMode(.multicolor)

Symbol Weights

SF Symbols match font weights. Adjust the weight to match surrounding text:

HStack {
    Text("Light")
        .fontWeight(.light)
    Image(systemName: "star.fill")
        .fontWeight(.light)
}

HStack {
    Text("Bold")
        .fontWeight(.bold)
    Image(systemName: "star.fill")
        .fontWeight(.bold)
}

Symbol Variants

Many symbols have variants: filled, outlined, slashed, or with badges. Use the .symbolVariant() modifier:

Image(systemName: "heart")
    .symbolVariant(.fill)  // heart.fill

Image(systemName: "bell")
    .symbolVariant(.slash)  // bell.slash

Image(systemName: "folder")
    .symbolVariant(.fill.badge.plus)  // folder.fill.badge.plus

This approach is cleaner than manually constructing symbol names.

Animated Symbols (iOS 17+)

iOS 17 introduced symbol effects for animated transitions:

// Bounce effect
Image(systemName: "bell.fill")
    .symbolEffect(.bounce, value: notificationCount)

// Pulse continuously
Image(systemName: "heart.fill")
    .symbolEffect(.pulse)

// Variable color animation
Image(systemName: "wifi")
    .symbolEffect(.variableColor.iterative)

For explicit control over when effects run:

struct AnimatedIcon: View {
    @State private var isAnimating = false

    var body: some View {
        Image(systemName: "arrow.down.circle.fill")
            .symbolEffect(.bounce, value: isAnimating)
            .onTapGesture {
                isAnimating.toggle()
            }
    }
}

Symbol Transitions

Animate changes between symbols:

struct PlayPauseButton: View {
    @State private var isPlaying = false

    var body: some View {
        Button {
            isPlaying.toggle()
        } label: {
            Image(systemName: isPlaying ? "pause.fill" : "play.fill")
                .contentTransition(.symbolEffect(.replace))
        }
    }
}

Finding the Right Symbol

Download the SF Symbols app from Apple to browse the complete library. You can search by name, category, or keyword. The app shows all variants and rendering modes for each symbol.

Common categories include:

  • Communication (mail, phone, message)
  • Weather (sun, cloud, rain)
  • Objects (folder, doc, book)
  • Devices (iphone, desktopcomputer, tv)
  • Connectivity (wifi, antenna, network)
  • Transportation (car, airplane, bicycle)
  • Human (person, figure, hand)
  • Nature (leaf, flame, drop)

Using Symbols in Labels and Buttons

The Label view is designed for symbol-text pairs:

Label("Settings", systemImage: "gear")

// Hide the text, keeping accessibility
Label("Settings", systemImage: "gear")
    .labelStyle(.iconOnly)

// Hide the icon
Label("Settings", systemImage: "gear")
    .labelStyle(.titleOnly)

In navigation and toolbars:

.toolbar {
    ToolbarItem(placement: .navigationBarTrailing) {
        Button {
            // Action
        } label: {
            Image(systemName: "plus")
        }
    }
}

Accessibility

SF Symbols used in Label or Button automatically get appropriate accessibility labels from the visible text. For standalone symbols, add your own:

Image(systemName: "xmark")
    .accessibilityLabel("Close")

For decorative symbols that don't add meaning:

Image(systemName: "sparkles")
    .accessibilityHidden(true)

Custom SF Symbols

You can create custom symbols that match the SF Symbols style using the SF Symbols app. Export a template, edit it in a vector editor, and import it back. Add the resulting SVG to your asset catalog with the "Symbol Image Set" type.

// Using a custom symbol from your asset catalog
Image("custom.symbol.name")

Custom symbols support the same features as system symbols: weights, scales, and rendering modes.

Tab Bar Icons

Tab bars work well with SF Symbols:

TabView {
    HomeView()
        .tabItem {
            Label("Home", systemImage: "house")
        }

    SearchView()
        .tabItem {
            Label("Search", systemImage: "magnifyingglass")
        }

    ProfileView()
        .tabItem {
            Label("Profile", systemImage: "person")
        }
}

The system automatically handles selected/unselected states and applies appropriate colors.

Platform Considerations

Most SF Symbols are available across iOS, macOS, watchOS, and tvOS, but some are platform-specific. The SF Symbols app shows availability for each symbol. When using a symbol that might not be available, you can provide a fallback:

if #available(iOS 16, *) {
    Image(systemName: "shareplay")
} else {
    Image(systemName: "person.2")
}

SF Symbols integrate naturally with SwiftUI and should be your first choice for icons. They're free, constantly updated by Apple, and automatically match system appearance and accessibility settings.

subscribe.sh

// Stay Updated

Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.

>

By subscribing, you agree to our Privacy Policy.