# Creating a reactive TextField in Flutter

In this article, I will show you how you can very easily create a reactive TextField in Flutter.

# Motivation

A few months ago, while working on a client project, I was building multiple pages in a row which all contained some kind of form, like a login-, registration- and personal details form.

I soon got annoyed with all sorts of things related to building these forms...

1. Each page had to be Stateful (`StatefulWidget`).
    
2. All the `TextEditingController`s and `FocusNode`s had to be created manually.
    
3. We had to think about disposing these `TextEditingController`s and `FocusNode`s.
    
4. The `TextEditingController`s had to be 'connected' with our state management.
    
5. Validation ended up in several places, depending on if the validation was client- or server-sided.
    

All of this resulted in a painful amount of boilerplate code.

And I was not having it...

# The Slider widget

A bit later, I had to create a form for my [Scavenger Hunt app](https://twitter.com/hashtag/ScavengerHuntApp) pet project. This form had only one `TextField`, but it also contained a `Slider`.

I realized the `Slider` was way simpler to work with. Its most important properties are: `value` and `onChanged`.  
With `value` you tell the `Slider` its current value, and with `onChanged` you receive the value the user changed the slider to. No hassle of dealing with controllers.

So I was thinking, what if I could make a TextField that works the same way?

# A Reactive TextField was born

After playing around with some ideas, I ended up with something that can be used like this:

```dart
ReactiveTextField(
  text: state.counter.toString(),
  onChange: context.read<CounterCubit>().setValue,
  error: state.error,
),
```

As you can see, there are no controllers to deal with. Its properties can be directly connected with the state management solution of your choosing.

Below you can see its implementation.

```dart
class ReactiveTextField extends StatefulWidget {
  const ReactiveTextField({
    super.key,
    required this.text,
    required this.onChange,
    this.error,
  });

  final String text;
  final void Function(String text) onChange;
  final String? error;

  @override
  State<ReactiveTextField> createState() => _ReactiveTextFieldState();
}

class _ReactiveTextFieldState extends State<ReactiveTextField> {
  // ReactiveTextField will hold onto its own TextEditingController and Focusnode,
  // which you otherwise had to create and maintain yourself.
  final _controller = TextEditingController();
  final _focusNode = FocusNode();

  @override
  void initState() {
    super.initState();

    _controller.text = widget.text;
  }

  @override
  void didUpdateWidget(covariant ReactiveTextField oldWidget) {
    super.didUpdateWidget(oldWidget);
    // This is an important part!
    // Without this check, there will be an infinite loop!
    if (widget.text != _controller.text) {
      _controller.text = widget.text;
     // We remove focus, because the value has been set
     // from a different source.
      _focusNode.unfocus();
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    _focusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // ReactiveTextField simply wraps a 'normal' TextField.
    return TextField(
      controller: _controller,
      focusNode: _focusNode,
      onChanged: widget.onChange,
      decoration: InputDecoration(
        errorText: widget.error,
      ),
    );
  }
}
```

As you can see, it is very simple. The most 'tricky' part here is the `didUpdateWidget` section, which is needed to prevent an infinite update loop from happening.

This `ReactiveTextField` widget will manage its controller so the parent can remain a `StatelessWidget`. All you have to do as the user is set the current value and listen to the updates, THAT IS IT!

# Full example

[Check out this dartpad link for a full example!](https://dartpad.dev/?id=614b3f4ad618e39ee8cb3f20ab9c0801)

Let me know what you think!
