| name | ouds-ios-components-controls |
| description | Usage and code examples for OUDS iOS Controls components — OUDSCheckbox / OUDSCheckboxItem / OUDSCheckboxPicker / OUDSCheckboxIndeterminate, OUDSRadio / OUDSRadioItem / OUDSRadioPicker, OUDSSwitch / OUDSSwitchItem, OUDSSuggestionChip / OUDSFilterChip / OUDSChipPicker, OUDSPinCodeInput, OUDSPasswordInput, OUDSTextInput, OUDSTextArea. Load the ouds-ios-framework-usage skill first for imports, themes and image rules. |
| license | MIT |
OUDS Controls components
Prerequisite: load ouds-ios-framework-usage first for imports, themes and image rules
(OUDSImage, // swiftlint:disable:next accessibility_label_for_image).
Common patterns (shared across most Controls)
These patterns apply to Checkbox, Radio, Switch, TextInput, TextArea, PinCodeInput, PasswordInput unless noted otherwise.
| Pattern | Syntax |
|---|
| Error state | isError: true, errorText: "Message" |
| Rich error | errorText: AttributedString |
| Plain helper | helperText: "…" |
| Rich helper | helperText: AttributedString |
| Error status (inputs) | status: .error(message: "…") |
| Rich error status | status: .richError(message: AttributedString) |
| Read-only | isReadOnly: true |
| Disabled | .disabled(true) — never combine with isError or isReadOnly |
Forbidden combinations (fatal error at runtime): isError + isReadOnly, isError + .disabled, isReadOnly + .disabled
Checkbox
OUDSCheckbox(isOn: $isOn, accessibilityLabel: "Label")
OUDSCheckboxIndeterminate(selection: $selection, accessibilityLabel: "Label")
OUDSCheckboxItem("Label", isOn: $isOn)
OUDSCheckboxItem("Label", isOn: $isOn, description: "Helper",
icon: OUDSImage(asset: Image(decorative: "ic")))
OUDSCheckboxItem("Label", isOn: $isOn,
icon: OUDSImage(asset: Image(decorative: "ic")), isReversed: true)
OUDSCheckboxItem("Label", isOn: $isOn,
icon: OUDSImage(asset: Image(decorative: "il_brand"), renderingMode: .original))
OUDSCheckboxItem("Label", isOn: $isOn,
icon: OUDSImage(asset: Image(systemName: "figure.handball"),
flipped: layoutDirection == .rightToLeft))
OUDSCheckboxItem(LocalizedStringKey("agree_terms"), bundle: Bundle.module, isOn: $isOn,
icon: OUDSImage(asset: Image(decorative: "ic")))
(, selection: ,
icon: (asset: (decorative: )))
((), bundle: .module,
selection: )
Parameter order: (_ label:, isOn:, description:, icon:, isReversed:, isError:, errorText:, isReadOnly:, hasDivider:, constrainedMaxWidth:, action:)
OUDSCheckboxPicker(selections: $selections, checkboxes: [
.init(tag: "a", label: "Option A"),
.init(tag: "b", label: "Option B", description: "Details", isReversed: true),
.init(tag: "c", label: "Option C", icon: OUDSImage(asset: Image(systemName: "flame"))),
.init(tag: "d", label: "Option D",
icon: OUDSImage(asset: Image(decorative: "il_brand"), renderingMode: .original)),
])
OUDSCheckboxPicker(selections: $selections, checkboxes: data,
placement: .verticalRooted("All options", .textAndCount))
OUDSCheckboxPicker(selections: $selections, checkboxes: data,
isReversed: true, placement: .horizontal(true))
Radio Button
OUDSRadio(isOn: $isOn, accessibilityLabel: "Label")
OUDSRadioItem("Label", isOn: $isOn)
OUDSRadioItem("Label", isOn: $isOn, icon: OUDSImage(asset: Image(decorative: "ic")))
OUDSRadioItem("Label", isOn: $isOn,
icon: OUDSImage(asset: Image(decorative: "il_brand"), renderingMode: .original))
OUDSRadioItem("Label", isOn: $isOn,
icon: OUDSImage(asset: Image(systemName: "chevron.right"),
flipped: layoutDirection == .rightToLeft))
OUDSRadioItem(LocalizedStringKey("option_label"), bundle: Bundle.module, isOn: $isOn,
icon: OUDSImage(asset: Image(decorative: "ic")))
OUDSRadioPicker(selection: $selection,
radios: [
.init(tag: "a", label: "Option A"),
.init(tag: "b", label: "Option B",
icon: OUDSImage(asset: Image(systemName: ))),
.(tag: , label: ,
icon: (asset: (decorative: ),
renderingMode: .original)),
],
placement: .vertical)
Switch
OUDSSwitch(isOn: $isOn, accessibilityLabel: "Label")
OUDSSwitchItem("Label", isOn: $isOn)
OUDSSwitchItem("Label", isOn: $isOn,
icon: OUDSImage(asset: Image(decorative: "ic")))
OUDSSwitchItem("Label", isOn: $isOn,
icon: OUDSImage(asset: Image(decorative: "il_brand"), renderingMode: .original))
OUDSSwitchItem("Label", isOn: $isOn,
icon: OUDSImage(asset: Image(systemName: "figure.handball"),
flipped: layoutDirection == .rightToLeft))
OUDSSwitchItem(LocalizedStringKey("wifi_setting"), bundle: Bundle.module, isOn: $isOn,
icon: OUDSImage(asset: Image(decorative: "ic")))
Pin Code Input
Available lengths: .four, .six (default).
OUDSPinCodeInput($value)
OUDSPinCodeInput($value, length: .four, autofocus: true)
OUDSPinCodeInput($value, helperText: "Enter your PIN")
Password Input
status is of type OUDSTextInput.Status (shared with OUDSTextInput).
OUDSPasswordInput(label: "Password", password: $password, isHiddenPassword: $isHidden)
OUDSPasswordInput(label: "Password", password: $password, isHiddenPassword: $isHidden,
placeholder: "Min. 8 chars", prefix: "🔑", lockIcon: true)
Chips
OUDSSuggestionChip(text: "Label") {}
OUDSSuggestionChip(icon: OUDSImage(asset: Image("ic")), text: "Label") {}
OUDSSuggestionChip(icon: OUDSImage(asset: Image("ic"), renderingMode: .original), text: "Label") {}
OUDSSuggestionChip(icon: OUDSImage(asset: Image("ic")), accessibilityLabel: "Label") {}
OUDSSuggestionChip(icon: OUDSImage(asset: Image("ic"), renderingMode: .original), accessibilityLabel: "Label") {}
OUDSFilterChip(text: "Label") {}
OUDSFilterChip(icon: OUDSImage(asset: Image("ic")), text: "Label") {}
OUDSFilterChip(icon: OUDSImage(asset: Image("ic"), renderingMode: .original), text: "Label") {}
OUDSFilterChip(icon: OUDSImage(asset: Image("ic")), accessibilityLabel: "Label") {}
OUDSFilterChip(icon: OUDSImage(asset: Image("ic"), renderingMode: .original), accessibilityLabel: "Label") {}
OUDSChipPicker(title: , selection: , chips: [
.(tag: .value1, layout: .textAndIcon(, image: (asset: ()))),
.(tag: .value2, layout: .textAndIcon(, image: (asset: (), renderingMode: .original))),
.(tag: .value3, layout: .icon((asset: ()), accessibilityLabel: )),
.(tag: .value4, layout: .icon((asset: (), renderingMode: .original), accessibilityLabel: )),
])
Text Input
OUDSTextInput(label: "Label", text: $text)
OUDSTextInput(label: "Label", text: $text, placeholder: "…", prefix: "Pre", suffix: "Suf")
OUDSTextInput(label: "Label", text: $text, leadingIcon: OUDSImage(asset: Image("ic")))
OUDSTextInput(label: "Label", text: $text,
leadingIcon: OUDSImage(asset: Image("ic"), renderingMode: .original))
OUDSTextInput(label: "Label", text: $text,
leadingIcon: OUDSImage(asset: Image("ic"), flipped: layoutDirection == .rightToLeft))
OUDSTextInput(label: "Label", text: $text,
trailingAction: .init(icon: OUDSImage(asset: Image("ic")), actionHint: "Hint") {})
OUDSTextInput(label: "Label", text: $text,
trailingAction: .init(icon: OUDSImage(asset: Image("ic"), renderingMode: .original),
actionHint: "Hint") {})
Text Area
helperText type: .plain(String) | .rich(AttributedString) | .charactersMaxCount(UInt16)
OUDSTextArea(label: "Label", text: $text)
OUDSTextArea(label: "Label", text: $text, placeholder: "Describe…")
OUDSTextArea(label: "Label", text: $text, helperText: .plain("Max 500 chars."))
OUDSTextArea(label: "Label", text: $text, helperText: .charactersMaxCount(500))
OUDSTextArea(label: "Label", text: $text,
helperLink: .init(text: "Learn more") { openUrl(url) })
OUDSTextArea(label: "Label", text: $text, constrainedMaxHeight: true)
Height is controlled by two component tokens on theme.textArea:
sizeMinHeightInput (72 pt by default) — minimum height, always applied
sizeMaxHeightInput (240 pt by default) — maximum height before scroll (used when constrainedMaxHeight: false, the default)
When constrainedMaxHeight: true, maxHeight is capped to sizeMinHeightInput, keeping the component at a fixed compact size.