Loading...
Loading...
Implement and customize the SearchField widget for Flutter autocomplete functionality. Use when implementing search/autocomplete features, dropdown searches, or when the user mentions SearchField, autocomplete, or suggestion lists in Flutter.
npx skill4agent add maheshj01/skills flutter-searchfieldflutter pub add searchfieldpubspec.yamldependencies:
searchfield: ^2.0.0import 'package:searchfield/searchfield.dart';late List<SearchFieldListItem<YourType>> items;
YourType? selectedValue;
void initState() {
items = yourDataList.map((item) {
return SearchFieldListItem<YourType>(
item.searchableProperty, // Required: search performed on this
value: item.displayValue, // Optional: shown in input on selection
item: item, // Optional: custom object
child: customWidget, // Optional: custom suggestion widget
);
}).toList();
super.initState();
}SearchField<YourType>(
hint: 'Search placeholder',
suggestions: items,
selectedValue: selectedValue,
onSuggestionTap: (SearchFieldListItem<YourType> item) {
setState(() {
selectedValue = item;
});
},
onSearchTextChanged: (query) {
// Return filtered list based on query
if (query.isEmpty) return items;
return items.where((item) =>
item.searchKey.toLowerCase().contains(query.toLowerCase())
).toList();
},
)SearchField(
suggestions: ['Item 1', 'Item 2', 'Item 3']
.map((e) => SearchFieldListItem<String>(e))
.toList(),
suggestionState: Suggestion.expand,
onSuggestionTap: (item) {
// Handle selection
},
)SearchFieldListItem<City>(
city.name, // Search key
value: city.zipCode, // Value shown in input on select
item: city, // Full object for reference
child: Row( // Custom widget
children: [
Icon(Icons.location_city),
SizedBox(width: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(city.name, style: TextStyle(fontWeight: FontWeight.bold)),
Text(city.zipCode, style: TextStyle(fontSize: 12)),
],
),
],
),
)SearchField(
onTap: () async {
// Trigger initial load
final results = await fetchFromAPI();
setState(() => suggestions = results);
},
onSearchTextChanged: (query) {
// Filter or fetch based on query
return filteredSuggestions
.map((e) => SearchFieldListItem<String>(e))
.toList();
},
emptyWidget: Container(
height: 100,
child: Center(
child: CircularProgressIndicator(),
),
),
onScroll: (position, maxScroll) {
// Load more when near bottom
if (position > maxScroll * 0.8) {
loadMoreItems();
}
},
)searchInputDecorationsearchInputDecoration: SearchInputDecoration(
prefixIcon: Icon(Icons.search),
suffixIcon: Icon(Icons.arrow_drop_down),
hintStyle: TextStyle(color: Colors.grey),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2),
),
filled: true,
fillColor: Colors.grey[100],
)suggestionsDecoration: SuggestionDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
color: Colors.white,
hoverColor: Colors.grey.shade200,
)suggestionItemDecoration: SuggestionDecoration(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
color: Colors.grey.shade200,
borderRadius: BorderRadius.all(Radius.circular(2)),
)Form(
key: _formKey,
child: SearchField(
suggestions: validOptions.map((e) => SearchFieldListItem(e)).toList(),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please select an option';
}
if (!validOptions.contains(value)) {
return 'Please select a valid option';
}
return null;
},
autovalidateMode: AutovalidateMode.onUserInteraction,
),
)↑/↓Ctrl/Option + ↓Ctrl/Option + ↑EnterEscSearchField(
dynamicHeight: true,
maxSuggestionBoxHeight: 400, // Maximum viewport height
suggestions: items.map((item) =>
SearchFieldListItem(
item.name,
child: Container(
// Variable height content
child: Column(
children: [
Text(item.title),
if (item.hasSubtitle) Text(item.subtitle),
],
),
),
),
).toList(),
)SearchField(
suggestionDirection: SuggestionDirection.up, // Show above input
offset: Offset(0, 10), // Offset from input field
// Direction auto-adjusts based on available space
)suggestionsonSuggestionTaponSearchTextChangedselectedValuehintitemHeightdynamicHeightmaxSuggestionsInViewPortmaxSuggestionBoxHeightsuggestionStateSuggestion.expandSuggestion.hiddenautoCorrectenabledreadOnlykeepSearchOnSelectiontextInputActiontextCapitalizationtextAligninputFormattersSuggestionActiononTaponSubmitonOutsideTaponScrollshowEmptysearchInputDecorationsuggestionsDecorationsuggestionItemDecorationsearchStylesuggestionStylescrollbarDecorationmarginColorcontrollerfocusNodescrollControlleronSearchTextChangedonSearchTextChangedonSearchTextChanged: (query) {
if (query.isEmpty) return allSuggestions;
return allSuggestions.where((item) {
return item.searchKey.toLowerCase().contains(query.toLowerCase());
}).toList();
}selectedValueonSuggestionTap: (item) {
setState(() {
selectedValue = item;
});
}Form(
key: _formKey,
child: SearchField(
validator: (value) {
if (value == null || value.isEmpty) {
return 'Required field';
}
return null;
},
),
)