Working with SwiftUI Forms and Input
1. Creating Forms
| Property | Value | Description |
|---|---|---|
| Form | Form |
Root view for creating forms in SwiftUI |
| Section | Section |
Groups related form elements |
| TextField | TextField |
Allows user input for text values |
| Picker | Picker |
Provides selection from a list of options |
| Toggle | Toggle |
Boolean switch for on/off states |
| Stepper | Stepper |
Numeric input with increment/decrement controls |
Example: Basic Form Structure
struct ContentView: View {
@State private var name = ""
@State private var age = 0
@State private var isSubscribed = false
var body: some View {
Form {
Section(header: Text("Personal Information")) {
TextField("Name", text: $name)
Stepper("Age: " + String(age), value: $age, in: 0...120)
}
Section(header: Text("Preferences")) {
Toggle("Subscribe to newsletter", isOn: $isSubscribed)
}
}
}
}
Note: The
Form view automatically handles keyboard navigation and accessibility features.
2. Using TextField for Text Input
| Property | Value | Description |
|---|---|---|
| .textFieldStyle(_:) | TextFieldStyle |
Applies a style to the text field, such as rounded or bordered. |
| .onSubmit(of:action:) | SubmitScope |
Triggers an action when the user submits input (e.g., presses return). |
| .onChange(of:perform:) | Binding<String> |
Executes a closure when the text field's value changes. |
Example: Basic TextField Usage
struct ContentView: View {
@State private var userInput = ""
var body: some View {
TextField("Enter text", text: $userInput)
}
}
Example: TextField with Submission Handling
struct ContentView: View {
@State private var userInput = ""
var body: some View {
TextField("Type something", text: $userInput)
.onSubmit {
print("Submitted: \"\(userInput)\"")
}
}
}
Example: TextField with Validation
struct ContentView: View {
@State private var userInput = ""
@State private var isInvalid = false
var body: some View {
TextField("Enter name", text: $userInput)
.onChange(of: userInput) { newValue in
isInvalid = newValue.count < 3
}
.textFieldStyle(RoundedBorderTextFieldStyle())
.disabled(isInvalid)
}
}
3. Using SecureField for Passwords
| Property | Value | Description |
|---|---|---|
| SecureField | SecureField<String> |
A SwiftUI view for secure text input, typically used for passwords |
Example: SecureField in a Form
struct LoginForm: View {
@State private var password = ""
var body: some View {
Form {
Section(header: Text("Login")) {
SecureField("Password", text: $password)
.autocapitalization(.none)
.disableAutocorrection(true)
}
}
}
}
Note: SecureField automatically masks input characters and does not support text selection or copying.
Warning: Never log or store passwords in plain text. Always use secure storage mechanisms like Keychain Services.
4. Using Picker for Selection
| Property | Value | Description |
|---|---|---|
| selection | Binding<String> |
Binds the selected value to a state variable |
| label | Text |
Displays the label for the picker |
| menu | Menu |
Displays the picker as a menu (iOS 16+) |
Example: Basic Picker Usage
struct ContentView: View {
@State private var selectedFruit = "Apple"
let fruits = ["Apple", "Banana", "Orange", "Grape"]
var body: some View {
Form {
Picker("Select a fruit", selection: $selectedFruit) {
ForEach(fruits, id: \.self) { fruit in
Text(fruit)
}
}
}
}
}
Example: Picker with Custom Labels
struct ContentView: View {
@State private var selectedColor = "Red"
let colors = [
(name: "Red", hex: "#FF0000"),
(name: "Green", hex: "#00FF00"),
(name: "Blue", hex: "#0000FF")
]
var body: some View {
Form {
Picker("Select a color", selection: $selectedColor) {
ForEach(colors, id: \.name) { color in
HStack {
Text(color.name)
Spacer()
Text(color.hex).foregroundColor(.secondary)
}
}
}
}
}
}
Note: The
Picker view in SwiftUI is designed to work with a collection of values, typically strings or enums. It supports both Text and custom views for each item in the selection list.
Warning: When using
Picker inside a Form, ensure that the selection variable is properly initialized to avoid unexpected behavior or crashes.
5. Using DatePicker for Dates
| Property | Value | Description |
|---|---|---|
| date | Date |
The selected date value |
| displayedComponents | DatePickerComponents |
Defines which date components are displayed (e.g., .date, .hourAndMinute) |
| minimumDate | Date? |
Minimum selectable date |
| maximumDate | Date? |
Maximum selectable date |
Example: Basic DatePicker Usage
struct ContentView: View {
@State private var selectedDate = Date()
var body: some View {
DatePicker("Select Date", selection: $selectedDate, displayedComponents: .date)
}
}
Example: DatePicker with Time
struct ContentView: View {
@State private var selectedDateTime = Date()
var body: some View {
DatePicker(
"Select Date and Time",
selection: $selectedDateTime,
displayedComponents: [.date, .hourAndMinute]
)
}
}
Example: DatePicker with Date Range
struct ContentView: View {
@State private var selectedDate = Date()
let minDate = Calendar.current.date(byAdding: .day, value: -30, to: Date())!
let maxDate = Calendar.current.date(byAdding: .day, value: 30, to: Date())!
var body: some View {
DatePicker(
"Select Date",
selection: $selectedDate,
displayedComponents: .date,
minimum: minDate,
maximum: maxDate
)
}
}
Note: The
displayedComponents parameter allows you to control which parts of the date are shown in the picker. Common values include .date, .hourAndMinute, and .time.6. Using Stepper for Increments
| Property | Value | Description |
|---|---|---|
| value | Int |
The current value of the stepper |
| increment | Int |
The amount to increment by (default is 1) |
| step | Int |
The step size for each increment (default is 1) |
Example: Basic Stepper Usage
struct ContentView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
Stepper("Increment", value: $count)
}
}
}
Example: Stepper with Custom Increment
struct ContentView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Count: \(count)")
Stepper("Increment by 5", value: $count, step: 5)
}
}
}
7. Using Slider for Ranges
| Property | Value | Description |
|---|---|---|
| value | Double |
The current value of the slider |
| range | Range<Double> |
The minimum and maximum values the slider can take |
| step | Double |
Incremental steps for slider movement (optional) |
Example: Basic Slider Usage
struct ContentView: View {
@State private var sliderValue = 50.0
var body: some View {
VStack {
Text("Value: \(Int(sliderValue))")
Slider(value: $sliderValue, in: 0...100)
}
}
}
Example: Slider with Step
struct ContentView: View {
@State private var sliderValue = 0.0
var body: some View {
VStack {
Text("Value: \(Int(sliderValue))")
Slider(value: $sliderValue, in: 0...100, step: 5.0)
}
}
}
Note: The
Slider in SwiftUI is a two-way binding component, meaning it updates the state variable and reflects changes back to the UI.
8. Using Toggle for Boolean Values
| Property | Value | Description |
|---|---|---|
| isOn | Binding<Bool> |
The binding to the Boolean value that determines the toggle's state |
Example: Basic Toggle Usage
struct ContentView: View {
@State private var isSwitchOn = false
var body: some View {
Toggle("Enable Feature", isOn: $isSwitchOn)
}
}
Example: Toggle with Custom Label
struct ContentView: View {
@State private var notificationsEnabled = false
var body: some View {
Toggle(isOn: $notificationsEnabled) {
Text("Enable Notifications")
.font(.headline)
}
}
}
Note: The
isOn binding must be a @State or @Binding property to allow SwiftUI to update the toggle's state.
9. Using ColorPicker for Colors
| Property | Value | Description |
|---|---|---|
| ColorPicker | ColorPicker("Choose a color", selection: $color) |
Displays a color picker for selecting colors |
Note: The
ColorPicker is available in iOS 13 and later.10. Implementing Form Validation
| Property | Description | Usage |
|---|---|---|
| ValidationState | Represents the validation state of a form field | .valid, .invalid, .pending |
| errorMessage | Displays error message for invalid input | String value shown to user |
| isInvalid | Boolean indicating if field is invalid | Used to conditionally style fields |
Example: Basic Form Validation
struct ContentView: View {
@State private var name = ""
@State private var email = ""
@State private var isNameValid = true
@State private var isEmailValid = true
var body: some View {
Form {
TextField("Name", text: $name)
.onChange(of: name) { _ in
isNameValid = !name.isEmpty
}
TextField("Email", text: $email)
.onChange(of: email) { _ in
isEmailValid = email.contains("@")
}
Button("Submit") {
// Handle submission
}
.disabled(!isNameValid || !isEmailValid)
}
}
}
Example: Custom Validation Rule
struct EmailValidator {
static func isValid(_ email: String) -> Bool {
let emailRegEx = "^\\w+([\\.-]?\\w+)*@\\w+([\\.-]?\\w+)*(\\.\\w{2,3})+$"
let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
return emailPredicate.evaluate(with: email)
}
}
struct EmailField: View {
@Binding var email: String
@State private var isValid = true
var body: some View {
TextField("Email", text: $email)
.onSubmit {
isValid = EmailValidator.isValid(email)
}
}
}
Note: SwiftUI does not provide built-in validation, so custom logic is required for complex validation rules.