SwiftUI.cc
Snippets
ControlsSelectionBeginner

SwiftUI Picker Styles and Enum Selection

Picker binds a selection to tagged options. Drive it from a CaseIterable enum, choose menu, wheel, inline, or navigationLink styles, and group options with sections.

4 min readUpdated 2026-06
Enum-driven roast picker in a form
import SwiftUI

enum Roast: String, CaseIterable, Identifiable {
    case light, medium, dark
    var id: Self { self }
}

struct BrewSettings: View {
    @State private var roast: Roast = .medium

    var body: some View {
        Form {
            Picker("Roast", selection: $roast) {
                ForEach(Roast.allCases) { roast in
                    Text(roast.rawValue.capitalized).tag(roast)
                }
            }
            .pickerStyle(.menu)

            Picker("Grind", selection: .constant(2)) {
                ForEach(1...5, id: \.self) { n in
                    Text("Level \(n)").tag(n)
                }
            }
            .pickerStyle(.wheel)
        }
    }
}

Picker styles preview

Tags are the wiring

A picker is a binding plus options, and every option needs a tag whose type matches the binding. With String raw-value enums, Text(roast.rawValue).tag(roast) keeps choice and model in lockstep — no string-to-enum conversion code.

An Optional binding needs Optional tags: .tag(Optional(roast)) or .tag(Roast?.none) for a "no selection" row. Mismatched optionality is the most common reason a picker "does not update."

Style decides the interaction

.pickerStyle(.menu)            // compact popup — form default
.pickerStyle(.wheel)           // drum roller, good in sheets
.pickerStyle(.segmented)       // all options visible
.pickerStyle(.inline)          // expanded rows in a form
.pickerStyle(.navigationLink)  // drill into a selection list

.navigationLink requires a NavigationStack and suits long option lists; .inline suits short lists worth seeing at once.

Sections inside

Options can group with Section("Popular") { … } inside the picker content — menu and inline styles render the groupings.

Common mistakes

  • Int tags with a String binding (or vice versa) — selection silently never matches.
  • Wheel style in scrolling forms, where the wheel fights the scroll gesture.
  • Recreating the options array each render with unstable identity.

Related reference