Skip to main content
FioriSwiftUICore provides a set of form view components that share a consistent Fiori appearance and validation behaviour. Each component accepts a ControlState to move between normal, disabled, and read-only states, and most support an inline error message.

TextFieldFormView

A single-line text field with a title label, placeholder, character count, and optional validation error.

Key parameters

title
any View / AttributedString
required
Field label displayed above the input.
text
Binding<String>
required
Two-way binding to the input string.
placeholder
any View / AttributedString?
Placeholder text shown when the field is empty.
controlState
ControlState
default:".normal"
Interaction state: .normal, .disabled, or .readOnly.
errorMessage
AttributedString?
Inline error message shown below the field.
maxTextLength
Int?
Maximum allowed character count.
isCharCountEnabled
Bool
default:"false"
When true and maxTextLength is set, shows a live character counter.
isRequired
Bool
default:"false"
Appends a mandatory field indicator (defaults to *) to the title.

Usage

@State private var emailText = ""
@State private var emailError: AttributedString? = nil

TextFieldFormView(
    title: "Email address",
    text: $emailText,
    placeholder: "[email protected]",
    controlState: .normal,
    errorMessage: emailError,
    maxTextLength: 256,
    isCharCountEnabled: true,
    isRequired: true
)

NoteFormView

A multi-line text editor for longer input such as notes and comments.

Key parameters

text
Binding<String>
required
Two-way binding to the note string.
placeholder
any View / AttributedString?
Placeholder text shown when the editor is empty.
minTextEditorHeight
CGFloat?
Minimum height of the text editor. Must be greater than 44 to take effect.
maxTextEditorHeight
CGFloat?
Maximum height before the editor becomes scrollable.
maxTextLength
Int?
Maximum allowed character count.
isCharCountEnabled
Bool
default:"false"
Shows a live character counter when true and maxTextLength is set.

Usage

@State private var noteText = ""

NoteFormView(
    text: $noteText,
    placeholder: "Add a comment…",
    minTextEditorHeight: 88,
    maxTextLength: 500,
    isCharCountEnabled: true
)

KeyValueFormView

A read-friendly key–value row commonly used to display record fields.
KeyValueFormView(
    title: "Serial number",
    text: .constant("SN-20240301-0042"),
    controlState: .readOnly
)

TitleFormView

A section-title row used to group related form fields.
TitleFormView(title: "Contact information")

RatingControlFormView

A star-rating input paired with a title label.
@State private var rating: Int = 3

RatingControlFormView(
    title: "Overall rating",
    rating: $rating
)

SwitchView

SwitchView pairs a title label with a Toggle. It supports .normal, .disabled, and .readOnly states. In read-only state you can supply a custom stateLabel string that replaces the toggle.

Key parameters

title
any View / AttributedString
required
Label for the toggle row.
isOn
Binding<Bool>
required
Controls the toggle state.
stateLabel
any View / AttributedString?
Custom text to replace the toggle in read-only state.
description
any View / AttributedString?
Descriptive text rendered in the informationView below the row.
controlState
ControlState
default:".normal"
Interaction state: .normal, .disabled, or .readOnly.

Usage

@State private var notificationsEnabled = true

SwitchView(
    title: "Push notifications",
    isOn: $notificationsEnabled
)

// Read-only variant with a custom state label
SwitchView(
    title: "Network access",
    isOn: .constant(false),
    stateLabel: "Locked by your organization",
    description: "Contact your administrator to change this setting.",
    controlState: .readOnly
)
.informationViewStyle(.warning)

Building a complete form

struct ContactForm: View {
    @State private var firstName = ""
    @State private var lastName = ""
    @State private var notes = ""
    @State private var rating = 4
    @State private var receiveUpdates = false
    @State private var firstNameError: AttributedString? = nil

    var body: some View {
        ScrollView {
            VStack(spacing: 0) {
                TitleFormView(title: "Personal details")

                TextFieldFormView(
                    title: "First name",
                    text: $firstName,
                    placeholder: "Enter first name",
                    errorMessage: firstNameError,
                    isRequired: true
                )

                TextFieldFormView(
                    title: "Last name",
                    text: $lastName,
                    placeholder: "Enter last name"
                )

                TitleFormView(title: "Feedback")

                RatingControlFormView(
                    title: "Satisfaction",
                    rating: $rating
                )

                NoteFormView(
                    text: $notes,
                    placeholder: "Additional comments…",
                    maxTextLength: 1000,
                    isCharCountEnabled: true
                )

                SwitchView(
                    title: "Receive product updates",
                    isOn: $receiveUpdates
                )
            }
        }
    }

    private func validate() {
        if firstName.isEmpty {
            firstNameError = "First name is required."
        } else {
            firstNameError = nil
        }
    }
}
Validation is your responsibility — set errorMessage and controlState in response to your own validation logic. The form view components display the state you provide; they do not auto-validate.

Build docs developers (and LLMs) love