Design Converter
Education
Software Development Executive - III
Last updated on Jan 20, 2025
Last updated on Jan 13, 2025
SwiftUI forms are essential for creating intuitive and streamlined user interfaces in many apps, particularly those requiring data entry and user input. If you’ve interacted with the settings app on your iPhone or iPad, you’ve seen a perfect example of how forms organize and display information effectively. SwiftUI takes this concept and simplifies the process for developers, enabling you to create forms quickly and with platform-appropriate styling.
Forms in SwiftUI are more than just static content containers—they provide user interactive controls such as text fields, toggles, and pickers. These controls allow users to interact with your app seamlessly, whether filling out a user profile, selecting picker options, or configuring settings. By wrapping controls inside a form, SwiftUI automatically applies platform-specific styling and behavior, saving you time while ensuring a consistent user experience.
SwiftUI forms excel at grouping controls and organizing related items into clear sections. This structure helps users understand and navigate the form easily, especially when dealing with multiple data entry fields or configuration options. By using sections and headers, you can group related items logically and create a seamless user experience.
Another advantage is that forms automatically adapt to platform-appropriate styling. Whether your app is running on iOS, macOS, or watchOS, SwiftUI applies the correct style to match the platform’s design language. This ensures that your app feels native and polished without requiring extra effort for customization.
Creating a SwiftUI form starts with understanding how forms act as container views for organizing user input controls like text fields, toggles, and buttons. A form helps to group related items logically, providing a structured layout that looks native to the platform.
To set up a basic form, you can wrap input controls inside the Form
container view. This automatically applies platform-appropriate styling to ensure your form integrates seamlessly with the platform’s UI guidelines.
1import SwiftUI 2 3struct BasicFormView: View { 4 var body: some View { 5 Form { 6 Section(header: Text("User Information")) { 7 Text("Welcome to SwiftUI Forms!") 8 } 9 } 10 } 11}
In the above code, the form contains a single section with static content wrapped inside. The Section
and header allow you to organize your form into logical groups, which are critical when scaling to more complex forms.
Forms become truly interactive when you add user input controls such as text fields, toggles, and buttons. These controls allow users to provide input and take actions, making your forms dynamic and functional.
A TextField
allows users to enter strings or other data. You’ll often bind it to a @State
variable to capture the input value.
1struct TextFieldFormView: View { 2 @State private var name: String = "" 3 4 var body: some View { 5 Form { 6 Section(header: Text("Personal Details")) { 7 TextField("Enter your name", text: $name) 8 } 9 } 10 } 11}
Toggles are useful for letting users enable or disable settings. A Toggle
also uses a @State
variable to capture the on/off state.
1struct ToggleFormView: View { 2 @State private var isSubscribed: Bool = false 3 4 var body: some View { 5 Form { 6 Section(header: Text("Preferences")) { 7 Toggle("Subscribe to Newsletter", isOn: $isSubscribed) 8 } 9 } 10 } 11}
Buttons trigger actions when tapped. In a form, they are often used to submit or reset data.
1struct ButtonFormView: View { 2 @State private var isSubmitted: Bool = false 3 4 var body: some View { 5 Form { 6 Section(header: Text("Actions")) { 7 Button("Submit") { 8 isSubmitted = true 9 } 10 .alert(isPresented: $isSubmitted) { 11 Alert( 12 title: Text("Submitted"), 13 message: Text("Your form has been submitted."), 14 dismissButton: .default(Text("OK")) 15 ) 16 } 17 } 18 } 19 } 20}
You can combine controls to create comprehensive forms.
1struct CombinedFormView: View { 2 @State private var username: String = "" 3 @State private var acceptTerms: Bool = false 4 5 var body: some View { 6 Form { 7 Section(header: Text("User Information")) { 8 TextField("Username", text: $username) 9 Toggle("Accept Terms and Conditions", isOn: $acceptTerms) 10 } 11 12 Section { 13 Button("Save") { 14 print("Username: \(username), Accepted Terms: \(acceptTerms)") 15 } 16 } 17 } 18 } 19}
This code demonstrates a complete form where users can input a username, toggle a setting, and tap a button to save the data. The controls are organized into sections, improving clarity and usability.
SwiftUI provides powerful tools for styling and theming forms, ensuring they look visually consistent and match your app's design language. By using view modifiers, you can customize fonts, colors, spacing, and other visual attributes.
You can use modifiers like font
, foregroundColor
, and background
to apply styles to specific controls or sections within the form.
1struct StyledFormView: View { 2 @State private var username: String = "" 3 4 var body: some View { 5 Form { 6 Section(header: Text("User Details") 7 .font(.headline) 8 .foregroundColor(.blue)) { 9 TextField("Enter your username", text: $username) 10 .font(.body) 11 .foregroundColor(.black) 12 } 13 } 14 .background(Color.gray.opacity(0.1)) 15 } 16}
Here, the Section
header text is styled with a headline font and a blue color, while the TextField
adopts a body font with black text. The form’s background is lightly shaded, making the content stand out.
SwiftUI automatically applies platform-appropriate styling to forms, but you can further tailor this behavior with modifiers like listStyle
.
1struct ThemedFormView: View { 2 var body: some View { 3 Form { 4 Section(header: Text("Preferences")) { 5 Toggle("Enable Notifications", isOn: .constant(true)) 6 } 7 } 8 .listStyle(InsetGroupedListStyle()) // Best for iOS settings screens 9 } 10}
Using InsetGroupedListStyle
gives your form a modern, compact appearance, ideal for settings screens on iOS.
Effective grouping of form content improves readability and usability. SwiftUI’s Section
is essential for organizing forms into logical blocks with headers, footers, or dividers. This structure is particularly useful when dealing with multiple data entry fields or settings.
You can group related controls into sections with headers and optional footers.
1struct GroupedFormView: View { 2 @State private var email: String = "" 3 @State private var password: String = "" 4 5 var body: some View { 6 Form { 7 Section(header: Text("Login Information")) { 8 TextField("Email", text: $email) 9 SecureField("Password", text: $password) 10 } 11 12 Section(header: Text("Actions")) { 13 Button("Login") { 14 print("Logging in with \(email)") 15 } 16 } 17 } 18 } 19}
In this example, the Login Information
section groups the email and password fields, while the Actions
section separates the button, improving clarity.
Headers and footers provide context for grouped controls. You can use text or even other views for more detailed headers or footers.
1struct HeaderFooterFormView: View { 2 var body: some View { 3 Form { 4 Section(header: Text("Account Details"), footer: Text("Please ensure your email is valid.")) { 5 TextField("Email", text: .constant("")) 6 } 7 } 8 } 9}
If your form contains a large number of controls, you can nest sections or use custom SwiftUI views to further break down content.
1struct NestedFormView: View { 2 var body: some View { 3 Form { 4 Section(header: Text("Profile")) { 5 TextField("Name", text: .constant("")) 6 TextField("Age", text: .constant("")) 7 } 8 9 Section(header: Text("Settings")) { 10 Group { 11 Toggle("Enable Notifications", isOn: .constant(true)) 12 Toggle("Dark Mode", isOn: .constant(false)) 13 } 14 } 15 } 16 } 17}
Here, Group
helps to organize related toggles inside a section without adding a separate header.
By combining modifiers and grouping, you can create a fully styled and organized form.
1struct CustomFormView: View { 2 @State private var name: String = "" 3 @State private var notificationsEnabled: Bool = false 4 5 var body: some View { 6 Form { 7 Section(header: Text("User Profile") 8 .font(.title2) 9 .foregroundColor(.purple)) { 10 TextField("Name", text: $name) 11 .padding() 12 .background(Color.gray.opacity(0.2)) 13 .cornerRadius(8) 14 } 15 16 Section(header: Text("Preferences")) { 17 Toggle("Notifications", isOn: $notificationsEnabled) 18 .toggleStyle(SwitchToggleStyle(tint: .green)) 19 } 20 } 21 .listStyle(GroupedListStyle()) 22 .navigationTitle("Customize Form") 23 } 24}
This example combines logical grouping with custom fonts, colors, and backgrounds, creating a visually appealing and user-friendly experience.
Form validation ensures users provide correct and complete data. SwiftUI simplifies this process by letting you validate input fields dynamically and provide real-time feedback.
You can add input validation using @State
variables and conditional logic to check for errors.
1struct ValidationFormView: View { 2 @State private var email: String = "" 3 @State private var errorMessage: String = "" 4 5 var body: some View { 6 Form { 7 Section(header: Text("Enter Your Details")) { 8 TextField("Email", text: $email) 9 .onChange(of: email) { newValue in 10 if !isValidEmail(newValue) { 11 errorMessage = "Invalid email address" 12 } else { 13 errorMessage = "" 14 } 15 } 16 17 if !errorMessage.isEmpty { 18 Text(errorMessage) 19 .foregroundColor(.red) 20 .font(.caption) 21 } 22 } 23 24 Section { 25 Button("Submit") { 26 if email.isEmpty || !isValidEmail(email) { 27 errorMessage = "Please enter a valid email" 28 } else { 29 print("Email submitted: \(email)") 30 } 31 } 32 } 33 } 34 } 35 36 func isValidEmail(_ email: String) -> Bool { 37 // Simple regex to validate email 38 let regex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" 39 let predicate = NSPredicate(format: "SELF MATCHES %@", regex) 40 return predicate.evaluate(with: email) 41 } 42}
In this example:
onChange
modifier monitors user input and updates the validation message.For forms with multiple fields, track validation for each field and display errors collectively.
1struct AdvancedValidationFormView: View { 2 @State private var username: String = "" 3 @State private var password: String = "" 4 @State private var errors: [String] = [] 5 6 var body: some View { 7 Form { 8 Section(header: Text("User Credentials")) { 9 TextField("Username", text: $username) 10 SecureField("Password", text: $password) 11 } 12 13 if !errors.isEmpty { 14 Section(header: Text("Errors")) { 15 ForEach(errors, id: \.self) { error in 16 Text(error).foregroundColor(.red) 17 } 18 } 19 } 20 21 Section { 22 Button("Register") { 23 validateForm() 24 } 25 } 26 } 27 } 28 29 func validateForm() { 30 errors.removeAll() 31 if username.isEmpty { errors.append("Username is required.") } 32 if password.isEmpty { errors.append("Password is required.") } 33 if password.count < 6 { errors.append("Password must be at least 6 characters.") } 34 } 35}
This approach centralizes validation logic, making it easier to maintain.
Accessibility ensures your forms are usable by all individuals, including those with disabilities. SwiftUI provides built-in tools to enhance accessibility, such as labels, traits, and dynamic type support.
Accessibility labels describe UI elements to screen readers.
1TextField("Enter your email", text: .constant("")) 2 .accessibilityLabel("Email address field")
Accessibility hints provide additional guidance for using controls.
1Button("Submit") { 2 print("Form submitted") 3} 4.accessibilityHint("Submits the form with the entered data")
Dynamic type ensures your app respects the user’s text size preferences.
1Text("Your Information") 2 .font(.title) 3 .dynamicTypeSize(.large ... .xxLarge)
Use the Accessibility Inspector in Xcode to:
1struct AccessibleFormView: View { 2 @State private var name: String = "" 3 @State private var acceptTerms: Bool = false 4 5 var body: some View { 6 Form { 7 Section(header: Text("User Info") 8 .accessibilityAddTraits(.isHeader)) { 9 TextField("Name", text: $name) 10 .accessibilityLabel("Name field") 11 } 12 13 Section { 14 Toggle("Accept Terms and Conditions", isOn: $acceptTerms) 15 .accessibilityLabel("Accept terms and conditions toggle") 16 } 17 18 Section { 19 Button("Submit") { 20 print("Form Submitted") 21 } 22 .accessibilityHint("Submits the form with the entered details") 23 } 24 } 25 .navigationTitle("Accessible Form") 26 } 27}
This form uses accessibility labels, hints, and traits to provide clear descriptions for screen readers, making it more inclusive.
In SwiftUI, @State
and @Binding
property wrappers are key to connecting form inputs with your app's data. These wrappers ensure that changes in form controls dynamically update the app's state, creating a seamless and reactive interface.
The @State
property wrapper manages form input values locally within a SwiftUI view.
1struct StateBindingFormView: View { 2 @State private var name: String = "" 3 @State private var age: Int = 18 4 5 var body: some View { 6 Form { 7 Section(header: Text("Personal Information")) { 8 TextField("Enter your name", text: $name) 9 Stepper("Age: \(age)", value: $age, in: 1...100) 10 } 11 12 Section { 13 Text("Hello, \(name). You are \(age) years old.") 14 } 15 } 16 } 17}
Here:
name
and age
variables are updated dynamically as users interact with the text field and stepper.$
symbol binds the state variable to the form control, enabling two-way data flow.When sharing form inputs between views, use @Binding
. A parent view passes a binding to its child, allowing the child to modify the parent’s state.
Parent View
1struct ParentView: View { 2 @State private var username: String = "" 3 4 var body: some View { 5 ChildFormView(username: $username) 6 } 7}
Child View
1struct ChildFormView: View { 2 @Binding var username: String 3 4 var body: some View { 5 Form { 6 TextField("Enter your username", text: $username) 7 } 8 } 9}
Changes in the child’s text field directly update the parent’s username
state.
SwiftUI forms offer developers a robust framework for building user-friendly, dynamic, and interactive interfaces. By incorporating features like styling, validation, accessibility, and integration with app logic, you can create polished forms that enhance user experience and functionality. With SwiftUI’s simplicity and flexibility, you can streamline form creation while maintaining consistency across Apple platforms.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.