Collections and layout
SwiftUI: the Label view
Learn how to use the Label view in SwiftUI to pair an icon with a title, browse SF Symbols, use custom images, and switch styles with labelStyle.
8 minute lesson
The Label view shows an icon and a title together, as a single view.
That’s the key idea. Not an icon placed next to some text, but one semantic unit. “Calendar” with a calendar icon. SwiftUI treats them as one thing, and that unlocks some nice behaviors we’ll see below.
You create a Label by passing the title as the first argument, and the icon name to the systemImage parameter:
Label("Calendar", systemImage: "calendar")
This will be the result:

The string you pass to systemImage is the name of an SF Symbols icon. SF Symbols is Apple’s icon library, built into every Apple platform, with thousands of icons designed to align perfectly with the system font.
To find the name of the icon you want, download the free SF Symbols app from the Apple website. You can browse and search every symbol there. Search “calendar” and you’ll also find calendar.badge.plus, calendar.circle, and a dozen more variants.
Using your own images
If the icon you need is an image from your asset catalog instead of an SF Symbol, use the image parameter:
Label("Profile", image: "avatar")
For full control over the icon, use the initializer that takes two view builders, one for the title and one for the icon:
Label {
Text("Profile")
} icon: {
Image("avatar")
.resizable()
.frame(width: 24, height: 24)
.clipShape(Circle())
}
Showing only the icon, or only the title
Sometimes you want the same label to show just the icon, maybe in a compact toolbar. Don’t remove the title. Apply the labelStyle() modifier instead:
Label("Calendar", systemImage: "calendar")
.labelStyle(.iconOnly)
The built-in styles are .titleAndIcon, .titleOnly and .iconOnly. The default is .automatic, which lets the surrounding context decide.
Keeping the title around even when it’s hidden matters for accessibility. VoiceOver still reads “Calendar”, because the label knows what it represents.
Why not just an HStack?
You could build something that looks identical with an HStack containing an Image and a Text:
HStack {
Image(systemName: "calendar")
Text("Calendar")
}
My advice is to always prefer Label. Here’s why.
First, accessibility. A Label is one element for VoiceOver. The HStack version is two separate elements, and the icon might get announced on its own, which is just noise.
Second, adaptivity. Views like List, TabView, menus and toolbars know how to handle labels. A tab bar shows the icon above the title. A menu places the icon on the correct side for the locale. A toolbar might drop the title when space is tight. Label adapts to all these contexts for free. Your custom HStack doesn’t.
Third, alignment. In a List, labels align their icons and titles consistently across rows, even when the icons have different widths.
Lesson completed