Select
Select presents a collapsed, single-choice field and publishes one stable string or integer value.
Complete example
public ?string $priority = null;
public array $priorityOptions = [
['value' => 'routine', 'label' => 'Routine'],
['value' => 'urgent', 'label' => 'Urgent'],
['value' => 'critical', 'label' => 'Critical', 'disabled' => true],
];
<firstlight:select
:options="$priorityOptions"
native:model="priority"
label="Priority"
placeholder="Select a priority"
helper="Choose one priority."
/>
Props
| API | Accepted type | Purpose |
|---|---|---|
options |
array |
Simple strings, a value-to-label map, or rich option arrays. Labels must contain visible text. |
value / native:model |
string, int, or null |
Stable selection. Every non-null value must exactly match one option by type and value. |
searchable |
bool |
Forces search for a collection with 12 or fewer options. Collections with 13 or more are always searchable. |
variant |
field or chip |
Full field (default) or compact native trigger; chooser and selection semantics are unchanged. |
label |
string |
Visible field label. |
placeholder |
string |
Trigger text when the published value is null; it is not the accessible name. |
helper |
string |
Supporting text shown when there is no error. |
error |
string |
Error text and native error semantics; replaces helper text. |
required |
bool |
Communicates required state; PHP still owns validation. |
disabled |
bool |
Disables the trigger and all options. |
a11y-label |
string |
Explicit accessible label when a visible label is inappropriate. |
a11y-hint |
string |
Additional VoiceOver and TalkBack guidance. |
class |
string |
External EDGE layout utilities. |
Options and values
Simple strings use the same value and label:
['Routine', 'Urgent']
A map separates stable values from labels and may use all-string or all-integer keys:
['routine' => 'Routine', 'urgent' => 'Urgent']
Rich options accept only value, label, and optional disabled fields:
[
['value' => 10, 'label' => 'Routine'],
['value' => 20, 'label' => 'Urgent', 'disabled' => true],
]
Values in one collection must be unique and all strings or all integers. Matching is strict: integer 10 does not match string '10'. null means no selection and displays the placeholder. Empty options accept only null and produce an inert trigger.
Compact and searchable presentation
Set variant="chip" for an intrinsic-width picker trigger with the label and
accepted value inline, for example a hospital or provider selector. The
default is variant="field". iOS uses a native bordered capsule trigger;
Android uses a Material 3 AssistChip. This changes the closed trigger only:
menus, search threshold, stable values, required/error/disabled metadata and
state timing remain unchanged. Chips retain 44-point iOS / 48-dp Android
targets rather than shrinking the touch area to the text.
<firstlight:select
variant="chip"
:options="['north' => 'North', 'south' => 'South']"
native:model="hospital"
label="Hospital"
/>
Declare public ?string $hospital = 'north'; on the screen.
Select chooses its platform presentation from the option count. Up to 12 options use a compact menu or dropdown. Thirteen or more options use a searchable presentation automatically. Set searchable to force search for a smaller collection.
Search filters labels locally in authored order. Typing, dismissing search, or selecting the accepted value does not publish an event. The iOS searchable sheet Done action is package chrome; see Localize chrome.
Events and state timing
@change receives the proposed stable scalar with its authored PHP type. native:model normally generates this callback for property synchronisation.
Select is server-authoritative. Choosing an enabled option emits immediately, but the trigger continues to show PHP's accepted value until the next publication. Further choices are ignored while that proposal is in flight. Rejected and programmatic publications do not emit.
An unchanged PHP response must also release the pending-interaction guard.
Host the control in FirstlightUI\NativeComponent for the
nonstreaming response-revision contract.
Revisions are not per-event acknowledgements
and do not prevent coalescing or serialize simultaneous proposals.
Use plain native:model or native:model.live; deferred blur and debounce modes are rejected.
Disabled, required, and error behaviour
disabled prevents the trigger and every option from emitting. A rich option's disabled: true affects only that choice. required communicates state but does not add client-side validation. Publish error from PHP when validation fails; it replaces helper text on both platforms.
Accessibility
Provide either a visible label or an explicit a11y-label. Firstlight warns during development when both are blank. The trigger exposes its accessible name, accepted value or placeholder, hint, required state, disabled state, and error. Option rows expose labels, selection, and disabled state. Native search retains editable-text semantics, labels wrap at accessibility sizes, and controls preserve platform minimum interaction targets.
Validation and failure behaviour
Contract exceptions still reject malformed options, type mismatches, and
unsupported presentation props before publication. User validation is
separate: screens that use ValidatesFields auto-bind the first MessageBag
message for the field's native:model or error-for name. An authored
error wins. required is display metadata and does not run Laravel rules.
See Validate fields.
Platform behaviour
iOS uses a SwiftUI Menu for compact collections and a native searchable sheet with checkmarked rows for searchable collections. Android uses a Material 3 exposed dropdown for compact collections and a searchable Material dialog with radio rows for searchable collections. Both preserve the same stable-value, disabled-option, threshold, publication, and stale-selection semantics.
Compatibility
Select supports the versions listed in the current compatibility reference and requires both native renderers in the host application plus Firstlight's screen response contract above. It does not require an unreleased runtime fix.
Screenshots
| Platform | Light | Dark |
|---|---|---|
| iOS | ![]() |
![]() |
| Android | ![]() |
![]() |



