flutter_autocomplete
Mobile-first autocomplete for Flutter with focused constructors:
AutocompleteField.single<T>()AutocompleteField.multiple<T>()AutocompleteField.async<T>()AutocompleteField.asyncMultiple<T>()
The package is built for touch/virtual-keyboard UX, chip-based multiple mode, async loading, creatable options, and visual grouping.
Installation
dependencies:
flutter_autocomplete: ^0.0.2
import 'package:flutter_autocomplete/flutter_autocomplete.dart';
Quick start
AutocompleteField<String>.single(
options: const ['Apple', 'Banana', 'Cherry'],
getOptionLabel: (option) => option,
decoration: const InputDecoration(
labelText: 'Fruit',
border: OutlineInputBorder(),
),
)
Demo
| 1) Single select (primitives) | 2) Single select (objects) | 3) Multiple chips |
|---|---|---|
![]() |
![]() |
![]() |
| 4) Creatable | 5) Grouped options | 6) Async search-as-type |
|---|---|---|
![]() |
![]() |
![]() |
| 7) Async combobox (load once) | 8) Async pagination | 9) Form validation |
|---|---|---|
![]() |
![]() |
![]() |
Constructor cheat sheet
| Constructor | Selection | Data source | Typical use |
|---|---|---|---|
single |
One value | Local list | Plain dropdown-like autocomplete |
multiple |
Many values | Local list | Chips/tag picker |
async |
One value | API/DB | Search-as-type or combobox |
asyncMultiple |
Many values | API/DB | Remote-backed chip picker |
Use case cookbook
1) Single select with primitive options
AutocompleteField<String>.single(
options: const ['Open', 'In Progress', 'Done'],
value: status,
onChanged: (value) => setState(() => status = value),
getOptionLabel: (option) => option,
)
2) Single select with objects + custom equality
Use isOptionEqualToValue when object identity may differ.
AutocompleteField<User>.single(
options: users,
value: selectedUser,
onChanged: (value) => setState(() => selectedUser = value),
getOptionLabel: (user) => user.fullName,
isOptionEqualToValue: (option, value) => option.id == value.id,
)
3) Multiple chips with fixed values
AutocompleteField<String>.multiple(
options: const ['Owner', 'Reviewer', 'Approver', 'Observer'],
values: selectedRoles,
onChanged: (values) => setState(() => selectedRoles = values),
getOptionLabel: (option) => option,
chipConfig: const AutocompleteChipConfig<String>(
fixedValues: ['Owner'],
limitTags: 3,
showHiddenCountChip: true,
),
behaviorConfig: const AutocompleteBehaviorConfig(
closeOnSelect: false,
clearInputOnSelect: true,
),
)
4) Creatable options
AutocompleteField<String>.multiple(
options: const ['bug', 'feature', 'blocked'],
values: tags,
onChanged: (values) => setState(() => tags = values),
getOptionLabel: (option) => option,
creatableConfig: AutocompleteCreatableConfig<String>(
createOption: (input) => input.trim().toLowerCase(),
createLabel: (input) => 'Create tag "$input"',
),
)
5) Grouping (visual only)
Grouping changes popup rendering only.
AutocompleteField<City>.single(
options: cities,
getOptionLabel: (city) => city.name,
groupingConfig: AutocompleteGroupingConfig<City>(
groupBy: (city) => city.country,
sortGroups: true,
stickyHeaders: true,
),
)
6) Async search-as-type
AutocompleteField<String>.async(
asyncConfig: AutocompleteAsyncConfig<String>(
optionsBuilder: repository.searchCities,
debounceDuration: const Duration(milliseconds: 250),
minQueryLength: 2,
reloadOnQueryChange: true,
),
getOptionLabel: (option) => option,
)
7) Async combobox (load once, then local filtering)
Useful when backend returns a bounded dataset.
AutocompleteField<String>.async(
asyncConfig: AutocompleteAsyncConfig<String>(
optionsBuilder: repository.fetchAllCities,
loadOnFocus: true,
reloadOnQueryChange: false,
loadOnlyOnce: true,
searchOnEmptyQuery: false,
debounceDuration: Duration.zero,
),
getOptionLabel: (option) => option,
)
8) Async multiple (load once)
AutocompleteField<String>.asyncMultiple(
asyncConfig: AutocompleteAsyncConfig<String>(
optionsBuilder: repository.fetchAllLabels,
loadOnFocus: true,
reloadOnQueryChange: false,
loadOnlyOnce: true,
searchOnEmptyQuery: false,
),
values: selectedLabels,
onChanged: (values) => setState(() => selectedLabels = values),
getOptionLabel: (option) => option,
)
9) Async pagination
AutocompleteField<String>.async(
asyncConfig: AutocompleteAsyncConfig<String>(
optionsBuilder: (_) async => const [],
loadOnFocus: true,
paginationConfig: AutocompleteAsyncPaginationConfig<String>(
pageSize: 20,
optionsPageBuilder: (query, page, pageSize) {
return repository.fetchPage(query: query, page: page, size: pageSize);
},
showEndOfListIndicator: true,
),
),
getOptionLabel: (option) => option,
)
10) Form validation and save
final formKey = GlobalKey<FormState>();
Form(
key: formKey,
child: Column(
children: [
AutocompleteField<String>.single(
options: const ['Low', 'Medium', 'High'],
getOptionLabel: (option) => option,
validator: (value) => value == null ? 'Priority is required' : null,
onSaved: (value) => priority = value,
),
AutocompleteField<String>.multiple(
options: const ['UI', 'Backend', 'QA'],
getOptionLabel: (option) => option,
validator: (values) {
if (values == null || values.isEmpty) {
return 'Select at least one team';
}
return null;
},
onSaved: (values) => teams = values ?? <String>[],
),
],
),
)
11) Custom rendering
AutocompleteField<String>.multiple(
options: const ['Apple', 'Banana', 'Cherry'],
getOptionLabel: (option) => option,
renderingConfig: AutocompleteRenderingConfig<String>(
optionBuilder: (context, option) {
return ListTile(
title: Text(option.label),
trailing: option.isSelected
? const Icon(Icons.check, size: 18)
: null,
);
},
),
)
12) Disabled options
AutocompleteField<String>.single(
options: const ['Open', 'Closed', 'Archived'],
getOptionLabel: (option) => option,
isOptionDisabled: (option) => option == 'Archived',
)
Async behavior reference
AutocompleteAsyncConfig gives these common patterns:
- Search-as-type:
reloadOnQueryChange: true - Load on focus:
loadOnFocus: true - One request only:
loadOnlyOnce: true - Ignore whitespace-only input:
searchOnEmptyQuery: false - Local filtering after first load:
reloadOnQueryChange: false
Useful config groups
AutocompleteBehaviorConfig: focus/open/close/clear behavior.AutocompleteFilterConfig: matching strategy and custom filter.AutocompleteSelectionConfig: keep selected rows visible and indicator behavior.AutocompleteChipConfig: chip layout, fixed values, hidden count, max chip area height.AutocompletePopupConfig: popup size/surface styling.AutocompleteRenderingConfig: option/selected/loading/empty custom builders.
Example app
A full runnable showcase exists in example/lib/main.dart.
It includes:
- Single and multiple local constructors.
- Creatable and grouped flows.
- Async search-as-type.
- Async load-once combobox and async multiple.
- Async pagination.
- Form validation and save flows.
Accessibility and platform scope
- Uses Flutter text/chip/tap semantics.
- Validation errors are rendered via
InputDecoration. - Mobile-first behavior.
Libraries
- flutter_autocomplete
- Public library exports for the
flutter_autocompletepackage.








