SwiftUI Tutorial · iOS 16+ · iOS 26 Liquid Glass

SwiftUI Picker: Segmented, Menu, Wheel & Enum Bindings

Choose the right Picker style for the job — segmented, menu, wheel, or navigation link — and bind cleanly to a CaseIterable enum with correct .tag() usage.

Last updated: 2026-07-17 9 min read By Ahmed Gagan, iOS Engineer
Quick Answer

A SwiftUI Picker binds a selection to a set of choices you list inside it, tagging each with .tag() so it matches the binding's type. Switch presentation with .pickerStyle: .segmented for a few options, .menu for a compact pop-up, .wheel for a spinning drum, and .navigationLink to push a selection screen. Bind it to a CaseIterable enum and iterate the cases with ForEach for type-safe options.

Core initializer
Picker(_:selection:) with tagged content
Styles
.segmented, .menu, .wheel, .navigationLink, .inline
Tagging
.tag(value) must match the selection's type
Swift Kit support
The Swift Kit's settings screen uses enum-bound pickers for theme and AI provider selection.

How a Picker binds to a selection

A Picker connects a selection binding to a list of options. Each option must carry a .tag whose value type exactly matches the binding, or the picker will silently show no selection — this is the single most common Picker bug. When you use a ForEach over Identifiable data, the id often supplies the tag automatically, but for anything else, attach .tag explicitly. Keep the tag type consistent: mixing an Int selection with String tags breaks the match.

Tagging options to match the binding
@State private var quantity = 1

Picker("Quantity", selection: $quantity) {
    ForEach(1...10, id: \.self) { n in
        Text("\(n)").tag(n)   // tag type Int matches $quantity
    }
}

Binding to a CaseIterable enum

The cleanest pickers bind to an enum. Make it String-backed, conform to CaseIterable and Identifiable, and you can iterate every case with ForEach while the compiler guarantees you handle only valid values. This pattern keeps your options and their display strings in one place and eliminates stringly-typed bugs. It also makes the selection trivially Codable for persistence in @AppStorage or a settings store.

An enum-backed theme picker
enum Theme: String, CaseIterable, Identifiable {
    case system, light, dark
    var id: Self { self }
    var label: String { rawValue.capitalized }
}

@State private var theme: Theme = .system

Picker("Appearance", selection: $theme) {
    ForEach(Theme.allCases) { theme in
        Text(theme.label).tag(theme)
    }
}

Choosing a picker style

The style you pick shapes the whole interaction, so match it to the number of options and the context. Segmented works best for two to four mutually exclusive choices shown inline. Menu is ideal in forms where space is tight — it collapses to the current value and expands on tap. Wheel suits ranges like time or quantity where scrubbing feels natural. NavigationLink pushes a dedicated selection list, which shines when options are numerous or need subtitles.

  • .segmented — 2 to 4 inline options, always visible
  • .menu — compact pop-up, great inside Forms
  • .wheel — spinning drum for ranges and dates
  • .navigationLink — pushes a full selection screen for long lists
  • .inline — expands all options directly in a List
The same picker in three styles
Picker("Sort", selection: $sort) {
    ForEach(SortOrder.allCases) { Text($0.label).tag($0) }
}
.pickerStyle(.segmented)   // or .menu, .navigationLink

// .navigationLink requires being inside a NavigationStack

Multi-component wheel pickers

To build a picker with several spinning columns — think a custom duration picker of hours and minutes — place multiple Pickers side by side in an HStack, each with .pickerStyle(.wheel) and its own binding. SwiftUI does not offer a single multi-column Picker type, so composing wheels is the idiomatic approach. Give each wheel a frame and clip it if you need tight spacing, and label the columns for accessibility.

An hours-and-minutes duration picker
@State private var hours = 0
@State private var minutes = 0

HStack(spacing: 0) {
    Picker("Hours", selection: $hours) {
        ForEach(0..<24, id: \.self) { Text("\($0) h").tag($0) }
    }
    .pickerStyle(.wheel)

    Picker("Minutes", selection: $minutes) {
        ForEach(0..<60, id: \.self) { Text("\($0) m").tag($0) }
    }
    .pickerStyle(.wheel)
}
.frame(height: 160)

Pickers inside Forms and iOS 26 notes

Dropped into a Form or List, a Picker automatically adopts the compact .menu style with a trailing chevron, which is the expected look for settings screens. You rarely need to set the style explicitly there. On iOS 26, form rows and menu pickers pick up the Liquid Glass material along with the rest of the system, so a picker built with the standard styles updates its look for free — no code changes required beyond running on the new SDK.

A picker row in a settings Form
Form {
    Section("Preferences") {
        Picker("Theme", selection: $theme) {
            ForEach(Theme.allCases) { Text($0.label).tag($0) }
        }
        // Renders as a compact menu row with a chevron
    }
}

Ship your SwiftUI app in 5 emails

A free 5-part course on the parts that actually stall launches: paywall, auth, onboarding, App Store review, and pricing. No fluff, unsubscribe anytime.

Settings screens, solved

The Swift Kit's settings module uses enum-bound pickers for theme and AI provider, so you get correctly tagged, persistable choices without the tag-matching headaches.

Get The Swift Kit — $99

Rather have it done for you? I set up and ship your app from $499. See how

Frequently Asked Questions

How do I make a segmented Picker in SwiftUI?
Apply .pickerStyle(.segmented) to a Picker. It works best for two to four mutually exclusive options shown inline. Make sure each option has a .tag whose type matches the selection binding.
Why is my SwiftUI Picker selection not updating?
Almost always the .tag value type does not match the selection binding's type — for example an Int selection with String tags. Ensure every option's tag matches exactly, and the picker will track the selection correctly.
How do I bind a SwiftUI Picker to an enum?
Make the enum CaseIterable and Identifiable, then iterate ForEach(MyEnum.allCases) inside the Picker, tagging each row with the case. Bind the picker's selection to a state property of that enum type.
How do I build a multi-column wheel Picker in SwiftUI?
SwiftUI has no single multi-component Picker, so place several Pickers with .pickerStyle(.wheel) in an HStack, each with its own binding. Give the stack a fixed height to size the wheels.
When should I use .menu versus .navigationLink Picker style in SwiftUI?
Use .menu for a compact pop-up when there are a handful of options and space is tight, especially inside Forms. Use .navigationLink when options are numerous or need subtitles, since it pushes a full selection list inside a NavigationStack.

Keep exploring

Stop writing settings plumbing

The Swift Kit is a $99 one-time SwiftUI boilerplate with a full settings screen, auth, and paywalls built in — lifetime updates and a 14-day refund.

Get The Swift Kit — $99

One-time purchase · Lifetime updates · 14-day refund