Structure
OUDSTextInput
Text input is a UI element that allows to enter, edit, or select single-line textual data. Text input is one of the most fundamental form elements used to capture user input such as names, emails, passwords, or search queries. It provides a visual and interactive affordance for text entry while supporting labels, placeholders, icons, descriptions, and validation feedback.
- iOS 15.0+
- macOS 13.0+
- visionOS 1.0+
@MainActor struct OUDSTextInput
Mentioned In
Layout
Text input is based on several configurable UI elements:
label: It is used to describe the purpose of the input. In some UI contexts, especially when space is limited or when the input is part of a compact layout (search bars, filters, inline forms), the label can be hidden. However, hiding the label should only be done if the purpose of the input remains clear thanks to a placeholder or contextual icon and if the label is still accessible to screen readers Hiding a label is a design choice that must balance visual simplicity and clarity of intent, without compromising inclusiveness or form guidance.
placeholder: if the text of the text input is empty a placeholder provides a hint or guidance inside the field to suggest expected input. A prefix and a suffix can be added to give more context.
leading icon: it helps indicate the purpose of the input (magnifying glass for search, envelope for email, phone device for phone number). Only use a leading icon if it adds clear functional or contextual value.
trailing action: it is used to provide actions related to the field: clear input, toggle password visibility, open a date picker, etc. Can also indicate status or feedback (error checkmark, loading spinner).
Outlined style
By default, the input is with a subtle background fill and invisible bottom border, creating a softer and more contained look. Best suited for dense layouts or to enhance visibility.
When outlined, the text input is a minimalist design with a transparent background and a visible stroke outlining the field. This style may be interesting for contexts other than form pages:
When inputs need to feel lightweight and unobtrusive
In a header (search field)
In a selection/filtering feature in a product catalog
// An outlined text input
OUDSTextInput(label: "Label", text: $text, isOutlined: true)
// With a localizable and a bundle
OUDSTextInput(LocalizedStringKey("label_wording"), bundle: Bundle.module, text: $text)
Rounded layout
Text input can have rounded layouts to be favored in more emotional, immersive contexts or those tied to specific visual identities. For standard or business-oriented journeys, keep the default corners. This evolution addresses the need for flexibility in adapting the design to some brand contexts.
To activate the rounded corner behavior, set to true the hasRoundedTextInputs values of the Tuning object in your theme configuration (if the theme exposes this property at init). Some themes do not have this flexibility like SoshTheme and WireframeTheme.
Status
Five status are proposed for all layouts:
default (by default): Default neutral appearance, whether empty or filled. It allows users to click, focus, and type freely without restrictions.
error: The error status indicates that the user input does not meet validation rules or expected formatting. It provides immediate visual feedback, typically through a red border, error icon, and a clear, accessible error message positioned below the input. The error messages replaces the helper text.
loading: The loading state indicates that the system is processing or retrieving data related to the text entered. A progress indicator appears to inform the user that an action is in progress.
readOnly :ThereadOnly, lets the text visible but not editable
disabled: In disabled status, the field is non-interactive and grayed out to indicate it cannot be changed. Note the SwiftUI View.disabled() is ignored.
Helpers
Helper text: A supporting text conveys additional information about the input field, such as how it will be used. It should ideally only take up a single line, though may wrap to multiple lines if required, and be either persistently visible or visible only on focus.
Helper link: If the helper text is not sufficient, it’s possible to offer the user an additional help link (the link can be external or open a modal).
Accessibility considerations
By default no haptics are done by the component for the trailing action. However you should think about cases wher you will have to make the devices vibrates. You can refer to the Human Interface Guidelines of Apple.
Mandatory field indication
If all fields are mandatory (several fields present): display the message “All fields are mandatory” at the top of your formular. Do not use an asterisk at the end of each field label, nor the word “mandatory.”
If not all fields are mandatory (several fields present): display the message “All fields marked with an * are mandatory” at the top of your formular. Use an asterisk (*) at the end of each mandatory field label, and ensures this is well vocalized.
UI rendering of the asterisk must be done with bold font weight and negative content color (red on light backgrounds).
Use the mention “(optional)” at the end of each optional field label. Note that this rule is not systematic, it remains an option, to be used if needed.
If there is only one field in the formular, or if the mandatory nature is obvious (such as login/password), no mention is necessary since the fields are essential to the formular’s functionality.
Rich text
Rich text can be used for error and helper texts.
Strong text can be used sparingly to highlight key information within the content. No other text styles should be used. Underlined text must not be applied manually (e.g. in error message), as it is commonly associated with hyperlinks and may mislead users.
Code samples
// The text to display and edit
@State var text: String = ""
// Empty text and no placeholder
OUDSTextInput(label: "Email", text: $text)
// Empty text with placeholder and suffix
OUDSTextInput(label: "Email", text: $text, placeholder: "firstName.lastName", suffix: "@orange.com")
// Empty text with prefix and suffix
OUDSTextInput(label: "Email", text: $text, prefix: "Distance", suffix: "km")
// Add a leading icon for more context
OUDSTextInput(label: "Email", text: $text, placeholder: "firstName.lastName", suffix: "@orange.com", leadingIcon: Image(systemName: "envelope"))
// Add a trailing button with local image namde "ic_cross" for additional action
let trailingAction = OUDSTextInput.TrailingAction(icon: Image("ic_cross"), actionHint: "Delete") { text = "" }
OUDSTextInput(label: "Email", text: $text, trailingAction: trailingAction)
// With helper text
OUDSTextInput(label: "Email",
text: $text,
placeholder: "firstName.lastName",
suffix: "@orange.com",
helperText: "The email will be automatically completed with @orange.com")
// With helper link
@Environment(\.openURL) private var openUrl
let helperLink = OUDSTextInput.HelperLink(text: "Helper Link") {
openUrl.callAsFunction(url)
}
OUDSTextInput(label: "Label", text: $text, placeholder: "Placeholder", helperLink: helperLink)
If you need to flip your icon depending to the layout direction or not (e.g. if RTL mode lose semantics / meanings):
@Environment(\.layoutDirection) var layoutDirection
OUDSTextInput(label: "Label", text: $text, flipLeadingIcon: layoutDirection == .rightToLeft)
Design documentation
unified-design-system.orange.com
Themes rendering
Orange

Orange Compact

Sosh

Wireframe

Version
1.3.0 (Figma component design version)
Since
0.20.0
Topics
Structures
Initializers
init(LocalizedStringKey, tableName: String?, bundle: Bundle, text: Binding<String>, placeholder: String?, prefix: String?, suffix: String?, leadingIcon: Image?, flipLeadingIcon: Bool, trailingAction: OUDSTextInput.TrailingAction?, helperText: AttributedString, helperLink: OUDSTextInput.Helperlink?, isOutlined: Bool, constrainedMaxWidth: Bool, status: OUDSTextInput.Status)Creates a text input with a localized label, looking up the key in the given bundle.
init(LocalizedStringKey, tableName: String?, bundle: Bundle, text: Binding<String>, placeholder: String?, prefix: String?, suffix: String?, leadingIcon: Image?, flipLeadingIcon: Bool, trailingAction: OUDSTextInput.TrailingAction?, helperText: String?, helperLink: OUDSTextInput.Helperlink?, isOutlined: Bool, constrainedMaxWidth: Bool, status: OUDSTextInput.Status)Creates a text input with a localized label, looking up the key in the given bundle.
init(label: String, text: Binding<String>, placeholder: String?, prefix: String?, suffix: String?, leadingIcon: Image?, flipLeadingIcon: Bool, trailingAction: OUDSTextInput.TrailingAction?, helperText: AttributedString, helperLink: OUDSTextInput.Helperlink?, isOutlined: Bool, constrainedMaxWidth: Bool, status: OUDSTextInput.Status)Creates a text input.
init(label: String, text: Binding<String>, placeholder: String?, prefix: String?, suffix: String?, leadingIcon: Image?, flipLeadingIcon: Bool, trailingAction: OUDSTextInput.TrailingAction?, helperText: String?, helperLink: OUDSTextInput.Helperlink?, isOutlined: Bool, constrainedMaxWidth: Bool, status: OUDSTextInput.Status)Creates a text input.
Instance Properties
Enumerations