Flutter DropdownSearch

Flutter simple and robust DropdownSearch with item search feature, making it possible to use an offline item list or filtering URL for easy customization.

Dropdown search

Key Features

  • Sync and/or Async items (online, offline, DB, …)
  • Searchable dropdown
  • Three dropdown mode: Menu/ BottomSheet/ ModalBottomSheet / Dialog
  • Single & multi selection
  • Material dropdown
  • Easy customizable UI
  • Handle Light and Dark theme
  • Easy implementation into statelessWidget
  • Support multi level items
Dropdown search Dropdown search
Dropdown search Dropdown search

packages.yaml

dropdown_search: <lastest version>

Import

import 'package:dropdown_search/dropdown_search.dart';

Simple implementation

DropdownSearch<String>(
    popupProps: PopupProps.menu(
        showSelectedItems: true,
        disabledItemFn: (String s) => s.startsWith('I'),
    ),
    items: ["Brazil", "Italia (Disabled)", "Tunisia", 'Canada'],
    dropdownDecoratorProps: DropDownDecoratorProps(
        dropdownSearchDecoration: InputDecoration(
            labelText: "Menu mode",
            hintText: "country in menu mode",
        ),
    ),
    onChanged: print,
    selectedItem: "Brazil",
)

DropdownSearch<String>.multiSelection(
    items: ["Brazil", "Italia (Disabled)", "Tunisia", 'Canada'],
    popupProps: PopupPropsMultiSelection.menu(
        showSelectedItems: true,
        disabledItemFn: (String s) => s.startsWith('I'),
    ),
    onChanged: print,
    selectedItems: ["Brazil"],
)

customize showed field (itemAsString)

DropdownSearch<UserModel>(
    asyncItems: (String filter) => getData(filter),
    itemAsString: (UserModel u) => u.userAsStringByName(),
    onChanged: (UserModel? data) => print(data),
    dropdownDecoratorProps: DropDownDecoratorProps(
        dropdownSearchDecoration: InputDecoration(labelText: "User by name"),
    ),
)

DropdownSearch<UserModel>(
    asyncItems: (String filter) => getData(filter),
    itemAsString: (UserModel u) => u.userAsStringById(),
    onChanged: (UserModel? data) => print(data),
    dropdownDecoratorProps: DropDownDecoratorProps(
        dropdownSearchDecoration: InputDecoration(labelText: "User by id"),
    ),
)

customize Filter Function

DropdownSearch<UserModel>(
    filterFn: (user, filter) =>
    user.userFilterByCreationDate(filter),
    asyncItems: (String filter) => getData(filter),
    itemAsString: (UserModel u) => u.userAsStringByName(),
    onChanged: (UserModel? data) => print(data),
    dropdownDecoratorProps: DropDownDecoratorProps(
        dropdownSearchDecoration: InputDecoration(labelText: "Name"),
    ),
)

customize Search Mode

DropdownSearch<UserModel>(
    popupProps: PopupProps.bottomSheet(),
    dropdownSearchDecoration: InputDecoration(labelText: "Name"),
    asyncItems: (String filter) => getData(filter),
    itemAsString: (UserModel u) => u.userAsString(),
    onChanged: (UserModel? data) => print(data),
)

Validation

DropdownSearch(
    items: ["Brazil", "France", "Tunisia", "Canada"],
    dropdownSearchDecoration: InputDecoration(labelText: "Name"),
    onChanged: print,
    selectedItem: "Tunisia",
    validator: (String? item) {
    if (item == null)
      return "Required field";
    else if (item == "Brazil")
      return "Invalid item";
    else
      return null;
    },
)

Endpoint implementation (using Dio package)

DropdownSearch<UserModel>(
    dropdownSearchDecoration: InputDecoration(labelText: "Name"),
    asyncItems: (String filter) async {
        var response = await Dio().get(
            "http://5d85ccfb1e61af001471bf60.mockapi.io/user",
            queryParameters: {"filter": filter},
        );
        var models = UserModel.fromJsonList(response.data);
        return models;
    },
    onChanged: (UserModel? data) {
      print(data);
    },
)

Layout customization

You can customize the layout of the DropdownSearch and its items. EXAMPLE

Full documentation here

Attention

To use a template as an item type, and you don’t want to use a custom function itemAsString and compareFn you need to implement toString, equals and hashcode, as shown below:

class UserModel {
  final String id;
  final DateTime createdAt;
  final String name;
  final String avatar;

  UserModel({this.id, this.createdAt, this.name, this.avatar});

  factory UserModel.fromJson(Map<String, dynamic> json) {
    if (json == null) return null;
    return UserModel(
      id: json["id"],
      createdAt:
          json["createdAt"] == null ? null : DateTime.parse(json["createdAt"]),
      name: json["name"],
      avatar: json["avatar"],
    );
  }

  static List<UserModel> fromJsonList(List list) {
    if (list == null) return null;
    return list.map((item) => UserModel.fromJson(item)).toList();
  }

  ///this method will prevent the override of toString
  String userAsString() {
    return '#${this.id} ${this.name}';
  }

  ///this method will prevent the override of toString
  bool userFilterByCreationDate(String filter) {
    return this.createdAt.toString().contains(filter);
  }

  ///custom comparing function to check if two users are equal
  bool isEqual(UserModel model) {
    return this.id == model.id;
  }

  @override
  String toString() => name;
}

View more Examples

Support

If this plugin was useful to you, helped you to deliver your app, saved you a lot of time, or you just want to support the project, I would be very grateful if you buy me a cup of coffee.

Buy Me A Coffee

License

MIT

GitHub

View Github