searchable_spinner
A modern, generic searchable dropdown/spinner for Flutter.
Built with Flutter's Material widgets only, so there are no runtime dependencies.
Features
- Generic
SearchableSpinner<T> - Local list filtering
- Async/API search
- Debounced search
- Optional pagination
- Custom item builder
- Clear selection
- Form validation
- Loading/error/empty states
- Material 3 friendly
- Light/dark theme compatible
- Responsive mobile, desktop and web layout
- No third-party runtime dependencies
Install
dependencies:
searchable_spinner: ^1.0.0
Local search
SearchableSpinner<Customer>(
items: customers,
value: selectedCustomer,
label: 'Customer',
hintText: 'Select customer',
itemLabel: (customer) => customer.name,
onChanged: (customer) {
setState(() => selectedCustomer = customer);
},
)
Custom item UI
SearchableSpinner<Customer>(
items: customers,
value: selectedCustomer,
itemLabel: (customer) => customer.name,
itemBuilder: (context, customer, selected) {
return ListTile(
leading: CircleAvatar(
child: Text(customer.name[0]),
),
title: Text(customer.name),
subtitle: Text(customer.email),
trailing: selected
? const Icon(Icons.check_circle)
: null,
);
},
onChanged: (customer) {
setState(() => selectedCustomer = customer);
},
)
Async/API search
SearchableSpinner<Customer>.async(
label: 'Customer',
itemLabel: (customer) => customer.name,
search: (query) async {
return repository.searchCustomers(query);
},
onChanged: (customer) {
setState(() => selectedCustomer = customer);
},
)
The query is automatically debounced.
Pagination
SearchableSpinner<Product>.async(
label: 'Product',
itemLabel: (product) => product.name,
search: (query) => repository.searchProducts(query, page: 1),
loadMore: (query, page) {
return repository.searchProducts(query, page: page);
},
onChanged: (product) {
selectedProduct = product;
},
)
When the user scrolls near the bottom, loadMore is called.
Validation
Form(
key: formKey,
child: SearchableSpinner<Customer>(
items: customers,
itemLabel: (customer) => customer.name,
onChanged: (value) {},
validator: (value) {
if (value == null) return 'Please select a customer';
return null;
},
),
)
Custom filtering
SearchableSpinner<Customer>(
items: customers,
itemLabel: (customer) => customer.name,
filter: (customer, query) {
return customer.name.toLowerCase().startsWith(query);
},
onChanged: (value) {},
)
Theme
SearchableSpinner<Customer>(
items: customers,
itemLabel: (customer) => customer.name,
theme: const SearchableSpinnerThemeData(
borderRadius: 18,
dialogWidth: 560,
itemHeight: 60,
),
onChanged: (value) {},
)
Publish
Before publishing, update the repository/homepage metadata in pubspec.yaml.
Run:
flutter pub get
dart format .
flutter analyze
flutter test
flutter pub publish --dry-run
flutter pub publish
Publishing a package is effectively permanent on pub.flutter-io.cn, so use the dry run and review metadata first.
License
MIT