# Message Composer State

`StreamMessageComposerController` manages the state of the message composer, including typed text, attachments, quoted messages, and editing state. It can be passed to `StreamMessageComposer` to programmatically read or control the composer from outside the widget. See the [pub.dev documentation](https://pub.dev/documentation/stream_chat_flutter_core/latest/stream_chat_flutter_core/StreamMessageComposerController-class.html) for the full API reference.

### Background

The `StreamMessageComposerController` is a controller class that embeds the business logic to compose a message.
`StreamMessageComposerController` is a parameter of the `StreamMessageComposer` widget.
Check the [`StreamMessageComposer` documentation](/chat/docs/sdk/flutter/stream-chat-flutter/message-composer/stream-message-composer/) to read more about that.

### Basic Example

Building a custom message input is a common task. Here is an example of how to use the `StreamMessageComposerController` to build a simple custom message input widget.

First of all we should create an instance of the `StreamMessageComposerController`.

```dart
class MessageScreenState extends State<MessageScreen> {
  final StreamMessageComposerController messageComposerController = StreamMessageComposerController();
```

Make sure you call `messageComposerController.dispose()` when the controller is no longer required.

```dart
@override
void dispose() {
  messageComposerController.dispose();
  super.dispose();
}
```

The `StreamMessageComposerController` is basically a `ValueNotifier` that notifies you when the message being composed has changed.
You can use a `ValueListenableBuilder` to build your UI depending on the latest message.
For a very simple message input you could even pass the `messageComposerController.textFieldController` to your `TextField` and set the `onChanged` callback.

```dart
...
Padding(
  padding: const EdgeInsets.all(8),
  child: Row(
    children: [
      Expanded(
        child: TextField(
          controller: messageComposerController.textFieldController,
          onChanged: (s) => messageComposerController.text = s,
          decoration: const InputDecoration(
            hintText: 'Enter your message',
          ),
        ),
      ),
      Material(
        type: MaterialType.circle,
        color: Colors.blue,
        clipBehavior: Clip.hardEdge,
        child: InkWell(
          onTap: () async {
            if (messageComposerController.message.text?.isNotEmpty ==
                true) {
              await channel.sendMessage(
                messageComposerController.message,
              );
              messageComposerController.clear();
              if (context.mounted) {
                _updateList();
              }
            }
          },
          child: const Padding(
            padding: EdgeInsets.all(8),
            child: Center(
              child: Icon(
                Icons.send,
                color: Colors.white,
              ),
            ),
          ),
        ),
      ),
    ],
  ),
),
...
```


---

This page was last updated at 2026-06-09T15:44:07.857Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/flutter/stream-chat-flutter-core/stream-message-composer-controller/](https://getstream.io/chat/docs/sdk/flutter/stream-chat-flutter-core/stream-message-composer-controller/).