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.

example_screenshot

Features

  • Single-selectAnyDropdownSingle<T> for picking one value.
  • Multi-selectAnyDropdownMulti<T> for picking a Set<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 stylinghasError flag for error state, onChanged: null for 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

Libraries

any_dropdown
A customizable dropdown widget library for Flutter.