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
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);
  },
)
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

Libraries

searchable_spinner