Persistent label above the well, never a placeholder. Bound to the field via htmlFor.
options *
ComboOption[]
n/a
Full option set; filtered live by what is typed (case-insensitive substring of label / secondary).
value *
string | string[]
n/a
Single selected value, or the array of selected values in multi-select.
onSelect *
(value: string) => void
n/a
Commit a selection (the option value). In multi-select, toggles the value in/out.
multiple
boolean
false
Render selected values as removable tokens inside the well; Backspace on an empty input pops the last.
onRemove
(value: string) => void
n/a
Remove a token (multi-select). Fired by its ✕ or by Backspace.
placeholder
string
n/a
Ghost prompt inside the well: supplementary, never the label.
helperText
string
n/a
Quiet helper line under the well.
disabled
boolean
false
Inert + clearly seen (never faded to invisible).
loading
boolean
false
Inline spinner in the well + a Searching… hint in the list (async source).
grouped
boolean
false
Bucket options under their group header.
ComboOption
Type
Default
Description
value *
string
n/a
Stable identity + the selected-value carrier.
label *
string
n/a
Primary line: the option’s accessible name (label.large role). The matched run is highlighted with a <mark>.
secondary
string
n/a
Supporting line under the label (body.small role).
status
'success' | 'warning' | 'error' | 'info' | 'idle'
n/a
Leading status mark color. Status colors only, never the brand cyan (cyan is reserved for the selected check).
group
string
n/a
Bucket name; options sharing a group render under one header when grouped.
disabled
boolean
false
Unselectable + skipped by the keyboard cursor, but still legible.
Parameter
Type
Default
Description
expanded *
Boolean
n/a
Whether the DropdownMenu is open. Hoisted state, toggled by the anchor + onDismissRequest.
onDismissRequest *
() -> Unit
n/a
Close the menu (tap-outside / back). Sets expanded = false.
modifier
Modifier
Modifier
External modifier on the menu, e.g. Modifier.fillMaxWidth(0.85f) to match the anchor width.
label *
String
n/a
DropdownAnchor: the current selection text (or a placeholder).
placeholder *
Boolean
n/a
DropdownAnchor: render the label muted as a placeholder when nothing is selected.
isLoading *
Boolean
n/a
DropdownAnchor: show an inline CircularProgressIndicator before the ▾.
enabled
Boolean
true
DropdownAnchor: when false, the anchor is dimmed + non-interactive (the filled surface).
onClick *
() -> Unit
n/a
DropdownAnchor: open the menu (guarded by enabled / isLoading / non-empty list).
DropdownMenuItem.enabled
Boolean
true
Per-row enablement; the empty state renders a single disabled “No X available” item.
SwiftUI has no single combobox control; the filterable pattern composes a TextField
bound to a .filter (HistorySection) and the fixed-select pattern is a Menu
(AppSettingsSection). These are the real parameters of those building blocks.
Style
Type
Default
Description
TextField(_:text:)
View
n/a
The query input. Bound to a @State String; style with .textFieldStyle(.plain) in a canvasAlt well + hairline border.
filter { … }
[T]
n/a
Live filter using localizedCaseInsensitiveContains(query) over each option’s label (the HistorySection idiom).
ContentUnavailableView
View
n/a
Empty / no-results state ("No matches", systemImage), never an error color.
Menu { Button … } label:
View
n/a
Fixed-select alternative: a borderless Menu of Button rows; label is the current selection + a chevron.up.chevron.down, accent-bordered.
.menuStyle(.borderlessButton)
MenuStyle
n/a
The Nockerl select menu style; pair with .menuIndicator(.hidden) to supply your own chevron.
Cross-platform drift (tracked for reconciliation)
The combobox is web-led. Only web ships the full type-to-filter + popover +
multi-select-token control. The native deltas:
Filtering(resolved): the combobox gains type-to-filter
everywhere. Android’s shipped selector (DropdownMenu + DropdownAnchor) is a fixed-list select
today; type-ahead (ExposedDropdownMenuBox + a query-filtered list) is the ratified target.
One control vs. composed: Swift has the pieces (a TextField+.filter
searchable list in HistorySection, a Menu select in AppSettingsSection) but
no single combobox component; they’re assembled per-screen.
Multi-select tokens: only web renders chosen values as removable chips inside the
field; Android/Swift have no token-in-field idiom for this yet.
Container radius: Swift’s wells/menus hardcode 8pt; the token is 12
(radius.control). Swift should consume radius.control.