FSAI Design System
Components

Select

Purpose-built select field built on top of Picker for standard choose-from-list form inputs.

Overview

Select is the standard choose-from-list field built on top of the Picker primitive.

It also composes the shared field-shell primitives:

  • Label for the field label
  • FieldError for inline validation feedback

It wraps the lower-level picker composition into a form-friendly field with:

  • optional label
  • optional labelIcon
  • built-in error display
  • placeholder support
  • optional in-menu search
  • optional multi-select
  • empty states

If you need a normal dropdown field, use Select before reaching for raw Picker.

Layering

ComponentRole
PickerBase primitive
LabelShared label primitive used by field components
FieldErrorShared inline validation-message primitive
SelectStandard field wrapper for choose-from-list selection
AutocompleteSelectSearch-first field for type-to-filter and async option discovery

Basic Usage

<Select
  label="Time Notation"
  selected={preferences.timeNotation}
  onSelect={handleUpdateTimeNotation}
  options={timeNotationOptions}
/>

This is the common settings and form-field pattern used in places like AccountPreferences.

Inline Workflow Select

Select also works well when the field is embedded inside a denser workflow UI instead of a traditional form layout.

<Select
  placement="bottom-end"
  options={[
    { value: 'read_only', label: 'Read Only' },
    { value: 'chat', label: 'Chat' },
    { value: 'admin', label: 'Admin' },
  ]}
  selected={field.value || 'chat'}
  onSelect={field.onChange}
/>

This is the pattern used in ChatOverview for participant permissions.

Multi-Select

<Select
  label="States"
  multiSelect
  options={stateOptions}
  selected={selectedStates}
  onSelect={setSelectedStates}
/>

Multi-select display behavior:

  • no selection: placeholder
  • one selection: selected option label or custom render
  • multiple selections: "{count} selected"

With Custom Option Content

Each option can include an icon, avatar, or render() function.

<Select
  selected={field.value}
  onSelect={field.onChange}
  onBlur={field.onBlur}
  error={errors?.status?.message}
  label="Location Status*"
  labelIcon="CircleHalfFill"
  size="sm"
  options={LOCATION_STATUS_OPTIONS.map((option) => ({
    value: option.value,
    label: option.label,
    render: () => (
      <Badge
        color={option.color}
        label={option.label}
        Icon={getLocationStatusIconName(option.value)}
      />
    ),
  }))}
/>

This mirrors the status field in CreateLocationModal, where the dropdown rows render badges instead of plain text.

Props

Shared Props

PropTypeDefaultDescription
options{ label, value, icon?, render?, avatar?, disabled? }[]Required. Available options.
labelstringField label shown above the trigger.
labelIconIconNameSmall icon next to the label.
idstringTrigger/input id.
requiredbooleanfalseAdds required asterisk in the label.
iconIconNameDefault left icon on the trigger.
placeholderstring'Select'Placeholder when nothing is selected.
searchablebooleanfalseAdds an in-menu search input.
onChangeSearchText(value: string) => voidCalled when the internal search text changes.
errorstring | nullShows field error below the control.
onBlur() => voidBlur handler for form integration.
size'sm' | 'md''md'Field size.
onListEndReached() => voidCalled when the bottom sentinel becomes visible.
disabledbooleanfalseDisables interaction.
classNamestringWrapper class name.
placementPlacement'bottom-start'Dropdown placement.
emptyStateTitlestringEmpty state title.
emptyStateDescriptionstringEmpty state description.
emptyStateAction{ label, onClick }Optional empty state action button.

Field Shell Props

These props are handled through Label and FieldError inside Select.

PropPrimitive usedDescription
labelLabelRenders the field label above the trigger.
labelIconLabelAdds a small icon inline with the label text.
requiredLabelAdds the required asterisk in the label row.
errorFieldErrorRenders inline validation feedback below the control.

Single Select Props

PropTypeDescription
selectedT | nullCurrent selected value.
onSelect(value: T) => voidRequired. Called when a value is selected.
multiSelectfalseSingle-select mode.

Multi-Select Props

PropTypeDescription
selectedT[]Current selected values.
onSelect(value: T[]) => voidRequired. Called with the updated set of selected values.
multiSelecttrueEnables multi-select behavior.

How Select Uses Picker

Internally, Select is a purpose-built composition of:

  • Picker root
  • Picker.Button as the trigger
  • Picker.Content as the dropdown panel
  • Picker.Content.Search when searchable is enabled
  • Picker.Item for option rows
  • Picker.Empty for empty state display
  • Label for the field label
  • FieldError for the validation message

That means Select inherits the picker value model and selection semantics, but presents them as a standard field component.

When To Use Select

Use Select when:

  • the user is choosing from a known list
  • the list fits a standard dropdown model
  • in-menu search is enough
  • the control should behave like a normal form field

Prefer AutocompleteSelect when:

  • typing is the main interaction
  • options are large enough that search-first interaction matters
  • grouping and search-first exploration matter more than dropdown simplicity
  • selected options can still be kept present in the available option set

Prefer raw Picker when:

  • you need a custom trigger
  • the control is not really a form field
  • you need a custom popup layout

Brand Dashboard Usage

Representative usages:

PatternPathNotes
Preferences fieldfsai/apps/brand-dashboard/src/pages/Account/AccountPreferences/AccountPreferences.tsxSimple labeled settings-field usage.
Inline workflow selectorfsai/apps/brand-dashboard/src/pages/Home/ChatOverview/ChatOverview.components.tsxCompact permission select inside a participant row.
Custom rendered optionsfsai/apps/brand-dashboard/src/modules/locations/components/CreateLocationModal/CreateLocationModal.tsxForm select with badge-rendered options.
Small action selectfsai/apps/brand-dashboard/src/pages/EmailBuilder/EmailEditorSidebar/EmailEditorSidebar.components.tsxSmall size="sm" control used to add a department.

Important Cautions

  • searchable is in-memory label filtering. It is not a full autocomplete pattern.
  • Object values must expose a stable id.
  • Select is a better default than raw Picker, but not a replacement for AutocompleteSelect.
  • If you need remote filtering or a search-first interaction, choose based on UX first, not because data happens to be async.

Guidelines

  • Do use Select as the default dropdown field in forms
  • Do use multiSelect only when the UI truly supports multi-value selection well
  • Do use searchable for medium-size in-memory option sets
  • Don't use Select for async typeahead experiences
  • Don't use raw Picker for ordinary form dropdowns unless you need custom composition

On this page