ElasticAutocomplete is a widget combines Autocomplete and LocalStorage.



  • It is easy to handle the option list by ElasticAutocompleteController and share the same options by id.
    • You can store data in local storage, which keeps data until users clean it.
    • You can also store data just in memory (like session storage), which keeps data until the program terminates.
    • You can use case-sensitive mode or case-insensitive mode when generating candidates. Nevertheless, if you want to generate candidates by yourself, you can set contains function instead.
  • You can generate fieldViewBuilder and optionsBuilder simply by ElasticAutocompleteController. However, if you don't want to use a controller, you can still set them two by yourself.


Example without controller

  • You can control the options list by optionsBuilder.
  • Besides, you can decorate TextFormField in fieldViewBuilder by yourself.
    optionsBuilder: (TextEditingValue textEditingValue) {
        if (textEditingValue.text == '') {
            return const Iterable<String>.empty();
        const List<String> options = [
        return options.where((String option) {
            return option.contains(textEditingValue.text);
    }, fieldViewBuilder: (BuildContext context,
        TextEditingController textEditingController,
        FocusNode focusNode,
        void Function() onFieldSubmitted) {
        return TextFormField(
            autofocus: true,
            // You must set controller, focusNode, and onFieldSubmitted 
            // in the textFormField
            controller: textEditingController,
            focusNode: focusNode,
            onFieldSubmitted: (String value) {
            decoration: const InputDecoration(
            border: OutlineInputBorder(),

Example with controller

  • It is easy for using ElasticAutocompleteController to load and set the options list.
  • Besides, it is easy to generate optionsBuilder and fieldViewBuilder.
  • You can set case sensitive or case insensitive in ElasticAutocompleteController to effect optionBuilder generated by controller automatically. Default is case-sensitive.
  • Unlike TextEditingController, ElasticAutocompleteController does not need disposed.
class MyWidgetState extends State<MyWidget> {
  final _formKey = GlobalKey<FormState>();
  late FocusNode _node;
  late ElasticAutocompleteController<String> _elasticAutocompleteCtrl;
  late TextEditingController _textEditingCtrl;

  void initState() {
    _node = FocusNode();
    _textEditingCtrl = TextEditingController();
    _elasticAutocompleteCtrl =
        ElasticAutocompleteController(id: 'example', caseSensitive: false);

  void dispose() {

  Widget build(BuildContext context) {
    return Form(
        key: _formKey,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
                controller: _elasticAutocompleteCtrl,
                // use optionsBuilder generated by controller
                optionsBuilder: _elasticAutocompleteCtrl.optionsBuilder,
                // use fieldViewBuilder generated by controller
                fieldViewBuilder: _elasticAutocompleteCtrl.fieldViewBuilder(
                    decoration: const InputDecoration(
                  border: OutlineInputBorder(),
                // use textEditingCtrl to get values in the TextFormField.
                textEditingController: _textEditingCtrl,
                // when setting the textEditingController, set the focusNode simultaneously.
                focusNode: _node),
            // store new value to the memory unit
                onPressed: () async {
                  if (_formKey.currentState?.validate() ?? false) {
                    String val = _textEditingCtrl.text;
                    // clear the text input field
                    // store to the memory unit
                    await _elasticAutocompleteCtrl.store(val);
                child: const Text("send")),
            // clear all options in the memory unit
              onPressed: () {
              child: const Text("clear"),