searchable_dropdown_form_field 0.1.1 copy "searchable_dropdown_form_field: ^0.1.1" to clipboard
searchable_dropdown_form_field: ^0.1.1 copied to clipboard

A customizable, searchable Flutter dropdown with form validation and generic value support.

Searchable Dropdown Form Field #

A customizable, generic Flutter dropdown with local or asynchronous search, form validation, dialog and bottom-sheet presentation, and full Material InputDecoration support.

Features #

  • Generic values with DropdownItem<T>
  • Fast local filtering with optional custom matching
  • Debounced asynchronous search for APIs and databases
  • Material dialog or modal bottom-sheet presentation
  • Form validation, saving, and auto-validation
  • Controlled values through value and onChanged
  • Clear button and selected-item checkmark
  • Custom value equality for model objects
  • Custom field, popup-item, title, search-input, and empty-state widgets
  • Theme-aware styling with no runtime dependency beyond Flutter

Installation #

Add the package to your pubspec.yaml:

dependencies:
  searchable_dropdown_form_field: ^0.1.1

Then import it:

import 'package:searchable_dropdown_form_field/searchable_dropdown_form_field.dart';

Basic usage #

The default behavior opens a searchable Material dialog. Existing synchronous dropdowns only need an item list and an onChanged callback.

String? selectedCountry;

CustomSearchableDropdown<String>(
  value: selectedCountry,
  hintText: 'Choose a country',
  dialogTitle: 'Select a country',
  items: const [
    DropdownItem(label: 'Bangladesh', value: 'BD'),
    DropdownItem(label: 'India', value: 'IN'),
    DropdownItem(label: 'Nepal', value: 'NP'),
  ],
  onChanged: (value) {
    setState(() => selectedCountry = value);
  },
);

Form validation #

CustomSearchableDropdown extends FormField<T>, so it works with normal Flutter forms.

final formKey = GlobalKey<FormState>();

Form(
  key: formKey,
  child: CustomSearchableDropdown<String>(
    items: countries,
    hintText: 'Country',
    validator: (value) => value == null ? 'Please select a country' : null,
    onSaved: (value) => selectedCountry = value,
  ),
);

Field and popup customization #

The closed field and popup search input use separate InputDecoration objects. Text styles, popup shape, padding, icons, and builders can also be configured independently.

CustomSearchableDropdown<String>(
  value: selectedCountry,
  items: countries,
  hintText: 'Choose a country',
  decoration: InputDecoration(
    labelText: 'Country',
    prefixIcon: const Icon(Icons.public),
    filled: true,
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(12),
    ),
  ),
  searchDecoration: InputDecoration(
    hintText: 'Type a country name or code',
    prefixIcon: const Icon(Icons.travel_explore),
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(12),
    ),
  ),
  textStyle: const TextStyle(fontWeight: FontWeight.w600),
  dialogTitleStyle: const TextStyle(
    fontSize: 22,
    fontWeight: FontWeight.bold,
  ),
  searchTextStyle: const TextStyle(fontSize: 16),
  itemTextStyle: const TextStyle(fontSize: 16),
  dialogShape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(20),
  ),
  showClearButton: true,
  showSelectedCheckmark: true,
  onChanged: (value) => setState(() => selectedCountry = value),
);

For complete control, use fieldBuilder, popupItemBuilder, dialogTitleWidget, or emptyResultWidget.

Custom search matching #

Local search matches item labels case-insensitively by default. Use searchMatcher to search additional fields such as country codes.

CustomSearchableDropdown<String>(
  items: countries,
  searchMatcher: (item, query) {
    final search = query.toLowerCase();
    return item.label.toLowerCase().contains(search) ||
        item.value.toLowerCase().contains(search);
  },
  onChanged: (value) => setState(() => selectedCountry = value),
);

Use asyncItemsLoader when results come from an API or database. Calls are debounced, stale responses are ignored, and loading, error, retry, and empty states are handled automatically. The selected async item's label remains visible after the popup closes, even when the original items list is empty.

CustomSearchableDropdown<User>(
  value: selectedUser,
  items: const [],
  hintText: 'Search users',
  popupMode: DropdownPopupMode.bottomSheet,
  searchDebounceDuration: const Duration(milliseconds: 300),
  asyncItemsLoader: (query) async {
    final users = await api.searchUsers(query);
    return users
        .map((user) => DropdownItem(label: user.name, value: user))
        .toList();
  },
  valueEquals: (first, second) => first.id == second.id,
  onChanged: (user) => setState(() => selectedUser = user),
);

Dialog presentation is the default:

popupMode: DropdownPopupMode.dialog

For a mobile-friendly modal sheet:

popupMode: DropdownPopupMode.bottomSheet

Selection controls #

CustomSearchableDropdown<String>(
  value: selectedCountry,
  items: countries,
  showClearButton: true,
  clearIcon: const Icon(Icons.close),
  showSelectedCheckmark: true,
  selectedIcon: const Icon(Icons.check_circle),
  onCleared: () => debugPrint('Selection cleared'),
  onChanged: (value) => setState(() => selectedCountry = value),
);

Main options #

Option Purpose
items Local dropdown items. Pass an empty list for async-only search.
value Currently selected value.
onChanged Called after selecting or clearing a value.
validator / onSaved Standard FormField<T> integration.
decoration Decoration for the closed dropdown field.
searchDecoration Decoration for the popup search input.
searchMatcher Custom local filtering logic.
asyncItemsLoader Loads items asynchronously for a query.
valueEquals Compares model values that do not implement equality.
popupMode Displays a dialog or modal bottom sheet.
showClearButton Allows the current selection to be cleared.
fieldBuilder Builds custom closed-field content.
popupItemBuilder Builds custom popup item content.

See the complete example for synchronous and asynchronous dropdowns.

3
likes
160
points
205
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A customizable, searchable Flutter dropdown with form validation and generic value support.

Homepage

License

MIT (license)

Dependencies

flutter

More

Packages that depend on searchable_dropdown_form_field