Hello everyone. I'm building a simple Form in a Multiplatform App with SwiftUI. Originally I had something like this.
import SwiftUI struct OnboardingForm: View { @State var firstName: String = "" @State var lastName: String = "" @State var email: String = "" @State var job: String = "" @State var role: String = "" var body: some View { Form { TextField("First Name", text: $firstName, prompt: Text("Required")) TextField("Last Name", text: $lastName, prompt: Text("Required")) TextField("Email", text: $email, prompt: Text("Required")) TextField("Job", text: $job, prompt: Text("Required")) TextField("Role", text: $role, prompt: Text("Required")) } } } #Preview { OnboardingForm() }
In macOS it looks ok but then in iOS it looks like this:
and it's impossible to know what each field is for if all the prompts are the same. I tried adding LabeledContent
around each text field and that solves it for iOS but then on macOS it looks like this:
The labels are shown twice and the columns are out of alignment. I think I could get around it by doing something like this:
#if os(iOS) LabeledContent { TextField("First Name", text: $firstName, prompt: Text("Required")) } label: { Text("First Name") } #else TextField("First Name", text: $firstName, prompt: Text("Required")) #endif
but it seems to me like reinventing the wheel. Is there a "correct" way to declare TextFields with labels that works for both iOS and macOS?
@alexortizl You can use a LabeledContent
and create a customLabeledContentStyle
that allows you customize the appearance.
struct CustomTextField: View { let label: String let prompt: String @Binding var text: String var body: some View { LabeledContent(label) { TextField(label, text: $text, prompt: Text(prompt)) } .labeledContentStyle(.customStyle) } } struct CustomLabeledContentStyle: LabeledContentStyle { func makeBody(configuration: Configuration) -> some View { #if os(macOS) configuration.content #else HStack { configuration.label configuration.content } #endif } } extension LabeledContentStyle where Self == CustomLabeledContentStyle { static var customStyle: CustomLabeledContentStyle { CustomLabeledContentStyle() } }
Form { CustomTextField(label: "First Name", prompt: "Required", text: $firstName) CustomTextField(label: "Last Name", prompt: "Required", text: $lastName) CustomTextField(label: "Email", prompt: "Required", text: $email) CustomTextField(label: "Job", prompt: "Required", text: $job) CustomTextField(label: "Role", prompt: "Required", text: $role) }