SwiftUI Form: Sections, Controls & a Settings Screen
Assemble a polished settings screen with Form — grouped and inset styles, sectioned controls, row backgrounds, and LabeledContent for clean read-only rows.
SwiftUI's Form is a container that lays out labeled controls in platform-standard grouped rows, ideal for settings and data-entry screens. Organize rows with Section, adding header and footer text for context. Drop in Toggle, Picker, Stepper, and TextField and they adopt the correct form styling automatically. Choose the look with .formStyle(.grouped), customize rows with .listRowBackground, and show read-only pairs with LabeledContent.
What a Form gives you for free
A Form is a specialized container that arranges its children as standard grouped rows, matching how Apple's own Settings app looks. Any control you place inside — a Toggle, a Picker, a TextField — automatically takes on form styling, including the label-on-the-left, control-on-the-right layout. This means you write far less layout code than with a hand-built VStack. Forms also handle scrolling, keyboard avoidance, and dynamic type without extra work, which is why they are the default choice for settings and entry screens.
Form {
Toggle("Notifications", isOn: $notificationsOn)
Toggle("Haptics", isOn: $hapticsOn)
Stepper("Reminders: \(count)", value: $count, in: 0...10)
}Form controls that belong inside
Forms shine because the standard controls know how to render inside them. A Picker collapses to a compact menu row with a chevron, a Toggle aligns its switch to the trailing edge, and a Stepper shows its plus and minus buttons on the right. TextField rows sit flush with a subtle divider. Because every control follows the same rules, a form built from these primitives looks native and consistent without any per-row styling on your part.
Section("Preferences") {
Picker("Theme", selection: $theme) {
ForEach(Theme.allCases) { Text($0.label).tag($0) }
}
Toggle("Reduce Motion", isOn: $reduceMotion)
Stepper("Font size: \(fontSize)", value: $fontSize, in: 12...24)
TextField("Display name", text: $name)
}Styling: form style and row backgrounds
Control the overall look with .formStyle. The .grouped style gives the classic separated cards, while .columns adapts layouts on macOS. To customize an individual row, apply .listRowBackground for a tinted card or .listRowInsets to adjust padding. Reach for these sparingly — a form's value is its consistency, so heavy per-row customization can make it feel off. On iOS 26, grouped forms inherit the Liquid Glass material automatically when built with standard components.
Form {
Section("Plan") {
LabeledContent("Current", value: "Pro")
Button("Manage Subscription") { openManage() }
.listRowBackground(Color.accentColor.opacity(0.12))
}
}
.formStyle(.grouped)LabeledContent for read-only rows
Not every row is editable. LabeledContent renders a label paired with a value or an arbitrary trailing view, which is the right tool for showing app version, account email, or a computed total. It handles alignment and truncation the same way system rows do, so your read-only rows match the editable ones. You can pass a plain value string or a full trailing view — an image, a colored status pill — when you need more than text.
Section("About") {
LabeledContent("Version", value: "2.4.1")
LabeledContent("Account", value: user.email)
LabeledContent("Status") {
Text("Active").foregroundStyle(.green)
}
}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.
A settings screen you don't have to build
The Swift Kit ships a complete settings Form — theme, account, subscription, and about sections — wired to real state, so you customize instead of starting from scratch.
Rather have it done for you? I set up and ship your app from $499. See how
How to build a Settings screen with SwiftUI Form
Assemble a real settings screen from sections and standard controls.
- 1
Wrap in NavigationStack
Put the Form in a NavigationStack and add a navigationTitle so it reads as a Settings screen.
NavigationStack { Form { ... }.navigationTitle("Settings") } - 2
Group into sections
Create a Section per topic — Account, Preferences, About — with a header for each.
Section("Preferences") { /* rows */ } - 3
Add controls
Fill sections with Toggle, Picker, Stepper, and LabeledContent rows bound to state.
Toggle("Dark Mode", isOn: $darkMode) - 4
Apply a form style
Set .formStyle(.grouped) for the classic separated-card appearance.
.formStyle(.grouped)
Frequently Asked Questions
How do I add a header and footer to a Section in a SwiftUI Form?
How do I change the background color of a form row in SwiftUI?
How do I show a read-only label and value row in a SwiftUI Form?
What is the difference between grouped and inset form styles in SwiftUI?
Why does my Picker look different inside a SwiftUI Form?
Keep exploring
Everything a real app needs, prebuilt
The Swift Kit is a $99 one-time SwiftUI boilerplate with settings, auth, AI, and paywalls already wired — lifetime updates and a 14-day refund.
Get The Swift Kit — $99One-time purchase · Lifetime updates · 14-day refund