A customizable dropdown widget for Flutter that supports any data type, single-select and multi-select modes, asynchronous option loading, and fully customizable trigger and menu delegates.

Features
- Single-select —
AnyDropdownSingle<T>for picking one value. - Multi-select —
AnyDropdownMulti<T>for picking aSet<T>of values. - Any data type — works with
String,int, enums, or custom classes. - Nullable support — nullable type parameters allow unselected states.
- Async options — fetch options from a network or database with built-in loading and error tracking.
- Fully customizable — swap trigger and menu delegates to match your design system.
- Widget-state styling —
hasErrorflag for error state,onChanged: nullfor disabled state, plus focus and hover styling on triggers and items. - Keyboard accessible — Enter and Space activate the dropdown; arrow keys navigate items.
Usage
Basic single-select
String _selected = 'Apple';
late final _provider = AnyDropdownListOptionProvider<String>(
optionsFetcher: () => ['Apple', 'Banana', 'Cherry'],
)..refreshOptions();
AnyDropdownSingle<String>(
value: _selected,
optionProvider: _provider,
menuDelegate: AnyDropdownSingleListMenuDelegate<String>(
_optionProvider: _provider,
),
triggerDelegate: const AnyDropdownSingleTriggerDelegate<String>(),
onChanged: (value) => setState(() => _selected = value!),
);
Multi-select
Set<String> _selected = {'Flutter'};
late final _provider = AnyDropdownListOptionProvider<String>(
optionsFetcher: () => ['Flutter', 'Dart', 'React', 'Vue'],
)..refreshOptions();
AnyDropdownMulti<String>(
value: _selected,
optionProvider: _provider,
menuDelegate: AnyDropdownMultiListMenuDelegate<String>(
_optionProvider: _provider,
),
triggerDelegate: const AnyDropdownMultiTriggerDelegate<String>(),
onChanged: (value) => setState(() => _selected = value),
);
Async options
late final _provider = AnyDropdownListOptionProvider<String>(
optionsFetcher: () async {
await Future.delayed(const Duration(seconds: 1));
return ['New York', 'London', 'Tokyo'];
},
)..refreshOptions();
Custom trigger and menu
Implement AnyDropdownTriggerDelegate<T> and AnyDropdownMenuDelegate<T, O>
(or extend the default delegates) to build your own trigger and menu widgets.
The buildTrigger method receives a bool isOpen parameter to reflect the
menu's open/closed state. See the
example app
for a chip-style trigger and a Material-styled menu with ink ripple and checkboxes.
Error state
Set hasError: true to apply error styling — triggers and menus render a red
border, and the selected value text turns red.
AnyDropdownSingle<String>(
value: _selected,
optionProvider: _provider,
menuDelegate: AnyDropdownSingleListMenuDelegate<String>(
_optionProvider: _provider,
),
triggerDelegate: const AnyDropdownSingleTriggerDelegate<String>(),
hasError: true,
onChanged: (value) => setState(() => _selected = value!),
);
Disabled state
Pass onChanged: null (or omit it) to disable the dropdown. The trigger becomes
non-interactive and renders a gray border and text. If the menu is open when the
dropdown becomes disabled, it is automatically closed.
AnyDropdownSingle<String>(
value: _selected,
optionProvider: _provider,
menuDelegate: AnyDropdownSingleListMenuDelegate<String>(
_optionProvider: _provider,
),
triggerDelegate: const AnyDropdownSingleTriggerDelegate<String>(),
// onChanged: null -> disabled
);
Additional information
- Example app — run the example to see all 7 usage scenarios.
- GitHub repository — report issues or contribute.
- pub.dev package — latest version and API reference.
Libraries
- any_dropdown
- A customizable dropdown widget library for Flutter.