How to enable Flutter user to enter tags into a FormBuilderTextField (Flutter Form Builder package)?

Viewed 1061

I'm building a form using the flutter_form_builder package (link to package on pub.dev) and would like to enable the user to enter tags into a FormBuilderTextField, mimicking StackOverflow's UI for entering tags (screenshot below).

screenshot of StackOverflow's UI for entering tags

Simple FormBuilderTextField, for reference:

FormBuilderTextField(
                      attribute: 'sampleAttribute',
                      decoration: InputDecoration(
                        labelText: "  Separate items,  with,  commas",
                        labelStyle: TextStyle(
                          fontSize: 12.0,
                          fontStyle: FontStyle.italic,
                        ),
                      ),
                    ),

This "Flutter - allow user enter hashtags" StackOverflow question was helpful, but doesn't really address this.

4 Answers

I tested many options and settled on the material_tag_editor 0.0.6 Flutter package.

Here's a screenshot from an iPhone simulator before any tags are entered:

screenshot with no tags entered

And here's a screenshot with two tags entered (using the comma as a delimiter), while in the middle of typing a 3rd tag:

screenshot while entering 3rd tag

Here's the code:

body: SingleChildScrollView(
    child: Container(
      child: Builder(
        builder: (context) => FormBuilder(
          // was "builder: (context) => Form("
          key: _formbuilderKey,
          initialValue: {
            'date': DateTime.now(),
          },
          child: Padding(
            padding: const EdgeInsets.all(14.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                SizedBox(
                  height: 12.0,
                ),
                RichText(
                  text: TextSpan(
                    style: TextStyle(
                      color: Colors.blue,
                    ),
                    children: <TextSpan>[
                      TextSpan(
                        text:
                            'In just a few words, what are 3 positive things about dogs?', // was 'What are 3 good or positive things about the house, property or neighborhood?', //  [ 1 ​]
                        style: TextStyle(
                          fontWeight: FontWeight.bold,
                          fontSize: 16.0,
                        ),
                      ),
                      TextSpan(
                        text: '  (optional)',
                        style: TextStyle(
                          fontWeight: FontWeight.normal,
                          fontStyle: FontStyle.italic,
                          fontSize: 14.0,
                          color: Colors.black54,
                        ), // was 'misleading or inaccurate?',
                      ),
                    ],
                  ),
                ),
                // BEGIN code from material_tag_editor
                Padding(
                  padding: const EdgeInsets.only(top: 16.0),
                  child: TagEditor(
                    length: somethingHere.length,
                    delimiters: [
                      ','
                    ], // was delimiters: [',', ' '],  Also tried "return" ('\u2386',)
                    hasAddButton: true,
                    textInputAction: TextInputAction
                        .next, // moves user from one field to the next!!!!
                    autofocus: false,
                    maxLines: 1,
                    // focusedBorder: OutlineInputBorder(
                    //   borderSide: BorderSide(color: Colors.lightBlue),
                    //   borderRadius: BorderRadius.circular(20.0),
                    // ),
                    inputDecoration: const InputDecoration(
                      // below was "border: InputBorder.none,"
                      isDense: true,
                      border: OutlineInputBorder(
                        borderRadius: const BorderRadius.all(
                          const Radius.circular(20.0),
                        ),
                      ),
                      focusedBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.lightBlue),
                        borderRadius: const BorderRadius.all(
                          const Radius.circular(20.0),
                        ),
                        // above is per https://github.com/flutter/flutter/issues/5191
                      ),
                      labelText: 'separate,  with,  commas',
                      labelStyle: TextStyle(
                        fontStyle: FontStyle.italic,
                        backgroundColor:
                            Color(0x65dffd02), // was Color(0xffDDFDFC),
                        color: Colors.black87, // was Color(0xffD82E6D),
                        fontSize: 14,
                      ),
                    ),
                    onTagChanged: (newValue) {
                      setState(() {
                        somethingHere.add(newValue);
                      });
                    },
                    tagBuilder: (context, index) => _Chip(
                      index: index,
                      label: somethingHere[index],
                      onDeleted: onDelete,
                    ),
                  ),
                ),
                // END code from material_tag_editor

What if you just have a Container with a Row, as well as a 'tag_view' widget?

The container would have a border like Stackoverflow has. The Row is scrollable and has multiple items:

Every Tag the user has added and an input field. Every time the user accepts a tag you add it to the list of tags.

For this you would just have a Row with a List of Widgets which holds different TagViews, and to the right there is always a TextField

Since you appear to know flutter I did this answer codeless, also the code for this would be pretty long to paste here, but this is how I would do it.

The reccomended Tags will be rather easy to handle, you would just put this all in a Stack, and put a List of Views on top that hold the reccomended Tags and whatever you want the view to be

consider using FormBuilderChipsInput for this functionality.

You can use textfield_tags flutter package to achieve this feature in your Flutter app. See the example below:

  import 'package:flutter/material.dart';
  import 'package:textfield_tags/textfield_tags.dart';

  void main() {
    runApp( MaterialApp(
        home: Home()
    ));
  }

  class Home extends  StatefulWidget {
    @override
    State<Home> createState() => _HomeState();
  }

  class _HomeState extends State<Home> {

    List<String> tags = ["flutter", "fluttercampus"]; //initial tags

    @override
    Widget build(BuildContext context) {
      return Scaffold(
          appBar: AppBar(
              title: Text("Enable Tag Input in TextField"),
              backgroundColor: Colors.redAccent,
          ),
            body: Container(
              alignment: Alignment.center,
              padding: EdgeInsets.all(20),
              child: Column(
                children:[
                      TextFieldTags(
                        textSeparators: [ 
                            " ", //seperate with space
                            ',' //sepearate with comma as well
                                
                        ],
                        initialTags: tags,
                        onTag: (tag){
                            print(tag);
                            //this will give tag when entered new single tag
                            tags.add(tag);
                        },
                        onDelete: (tag){
                            print(tag);
                            //this will give single tag on delete
                            tags.remove(tag);
                        },
                        validator: (tag){
                            //add validation for tags
                            if(tag.length < 3){
                                return "Enter tag up to 3 characters.";
                            }
                            return null;
                        },
                        tagsStyler: TagsStyler( //styling tag style
                            tagTextStyle: TextStyle(fontWeight: FontWeight.normal),
                              tagDecoration: BoxDecoration(color: Colors.blue[100], borderRadius: BorderRadius.circular(0.0), ),
                              tagCancelIcon: Icon(Icons.cancel, size: 18.0, color: Colors.blue[900]),
                              tagPadding: EdgeInsets.all(6.0)
                        ),
                        textFieldStyler: TextFieldStyler( //styling tag text field
                              textFieldBorder: OutlineInputBorder(
                                borderSide: BorderSide(color: Colors.blue, width: 2)
                              )
                        ),
                      ),

                      ElevatedButton(
                        onPressed: (){
                          print(tags);
                          //pint list of tags int the TextField
                        }, 
                        child: Text("Print Entered Tags")
                      )
                ]
              ),
            )
        );
    }
  }

Output of this code:

Tags Input Flutter App

Get the example here: How to Make Tags Input on TextField in Flutter

Related