Buy Me A Coffee

FindDropdown package - [ver em português]

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

Versions

Flutter 3.41.x / Dart 3.x: 1.0.2 or more

Null Safety (Dart 2.x): 1.0.0 – 1.0.1

Non Null Safety: 0.2.3 or less

RxDart 0.23.x or less: 0.1.7+1

pubspec.yaml

find_dropdown: ^1.0.2

Requires sdk: ">=3.0.0 <4.0.0" and Flutter 3.41.x+.

Import

import 'package:find_dropdown/find_dropdown.dart';

Simple implementation

FindDropdown<String>(
  items: const ["Brasil", "Itália", "Estados Unidos", "Canadá"],
  label: "País",
  onChanged: (String? item) => log('$item'),
  selectedItem: "Brasil",
);

Multiple selectable items

FindDropdown<String>.multiSelect(
  items: const ["Brasil", "Itália", "Estados Unidos", "Canadá"],
  label: "País",
  onChanged: (List<String> items) => log('$items'),
  selectedItems: const ["Brasil"],
);

FindDropdownChip (display as Chip)

FindDropdownChip shows selected item(s) as Material Design Chip widgets. In multiSelect mode, each chip has a delete button.

// Single selection
FindDropdownChip<String>(
  items: const ["Brasil", "Itália", "Estados Unidos", "Canadá"],
  label: "País",
  selectedItem: "Brasil",
  onChanged: (String? item) => log('$item'),
);

// Multiple selection (each chip has onDeleted)
FindDropdownChip<String>.multiSelect(
  items: const ["Flutter", "Dart", "Widget", "Material"],
  label: "Tags",
  selectedItems: const ["Flutter", "Dart"],
  showClearButton: true,
  onChanged: (List<String> items) => log('$items'),
);

Use chipBuilder to customize each chip. Use FindDropdownChipState and GlobalKey for clear() and setSelectedItem().

Validation

FindDropdown<String>(
  items: const ["Brasil", "Itália", "Estados Unidos", "Canadá"],
  label: "País",
  onChanged: (String? item) => log('$item'),
  selectedItem: "Brasil",
  validate: (String? item) {
    if (item == null) return "Required field";
    if (item == "Brasil") return "Invalid item";
    return null; // null means no error
  },
);

Endpoint implementation (using Dio package)

FindDropdown<UserModel>(
  label: "Nome",
  onFind: (String filter) async {
    final response = await Dio().get<List<dynamic>>(
      "http://5d85ccfb1e61af001471bf60.mockapi.io/user",
      queryParameters: {"filter": filter},
    );
    return UserModel.fromJsonList(response.data ?? []);
  },
  onChanged: (UserModel? data) => log('$data'),
);

Clear selected items

final countriesKey = GlobalKey<FindDropdownState<String>>();

Column(
  children: [
    FindDropdown<String>(
      key: countriesKey,
      items: const ["Brasil", "Itália", "Estados Unidos", "Canadá"],
      label: "País",
      selectedItem: "Brasil",
      showSearchBox: false,
      onChanged: (selectedItem) => log("country: $selectedItem"),
    ),
    ElevatedButton(
      onPressed: () => countriesKey.currentState?.clear(),
      child: const Text('Limpar Países'),
    ),
  ],
)

Change selected items

final countriesKey = GlobalKey<FindDropdownState<String>>();

Column(
  children: [
    FindDropdown<UserModel>(
      label: "Nome",
      onFind: (String filter) => getData(filter),
      searchBoxDecoration: const InputDecoration(
        hintText: "Search",
        border: OutlineInputBorder(),
      ),
      onChanged: (UserModel? data) {
        log('$data');
        countriesKey.currentState?.setSelectedItem("Brasil");
      },
    ),
    FindDropdown<String>(
      key: countriesKey,
      items: const ["Brasil", "Itália", "Estados Unidos", "Canadá"],
      label: "País",
      selectedItem: "Brasil",
      showSearchBox: false,
      onChanged: (selectedItem) => log("country: $selectedItem"),
    ),
  ],
)

MORE EXAMPLES

Theme customization

You can customize colors and typography using FindDropdownThemeData:

FindDropdown<String>(
  items: const ["Brasil", "Itália", "Estados Unidos", "Canadá"],
  label: "País",
  onChanged: (item) => log('$item'),
  selectedItem: "Brasil",
  theme: FindDropdownThemeData(
    dropdownBackgroundColor: Colors.grey.shade100,
    dropdownBorderColor: Colors.blue,
    iconColor: Colors.blueGrey,
    validationErrorColor: Colors.orange,
    fontFamily: 'Roboto',
    selectedItemStyle: TextStyle(fontSize: 16, color: Colors.black87),
  ),
);

Properties: dropdownBackgroundColor, dropdownBorderColor, iconColor, selectedItemStyle, validationErrorColor, validationMessageStyle, fontFamily. All are optional; when omitted, default values are used.

Layout customization

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

To customize the FindDropdown, we have the dropdownBuilder property, which takes a function with the parameters:

  • BuildContext context: current context;
  • T item: Current item, where T is the type passed in the FindDropdown constructor.

To customize the items, we have the dropdownItemBuilder property, which takes a function with the parameters:

  • BuildContext context: current context;
  • T item: Current item, where T is the type passed in the FindDropdown constructor.
  • bool isSelected: Boolean that tells you if the current item is selected.

Attention

To use a template as an item type, 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({
    required this.id,
    required this.createdAt,
    required this.name,
    required this.avatar,
  });

  @override
  String toString() => name;

  @override
  bool operator ==(Object other) => other is UserModel && other.id == id;

  @override
  int get hashCode => id.hashCode ^ name.hashCode ^ createdAt.hashCode;
}