# Typing Indicators

The Stream Flutter SDK displays typing indicators automatically when other channel members are composing a message. The indicator updates in real time as users start and stop typing.

### Default behavior

`StreamChannelHeader` shows a typing indicator in its subtitle by default via `StreamChannelInfo`. When one or more other users are typing, the subtitle shows their names and an animated dots icon. No configuration is required to enable this.

To show a typing indicator above the composer, add `StreamTypingIndicator` to `StreamMessageListView`'s `builders.header` slot — it renders at the bottom of the list (the default list is reversed, so the header builder paints below the most recent message):

```dart
StreamMessageListView(
  builders: StreamMessageListViewBuilders(
    header: (context) => Padding(
      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
      child: StreamTypingIndicator(),
    ),
  ),
)
```

### Theming

`StreamTypingIndicator` accepts a `style` parameter that controls the text appearance:

```dart
StreamTypingIndicator(
  style: const TextStyle(
    color: Colors.grey,
    fontStyle: FontStyle.italic,
  ),
)
```

The typing indicator shown in `StreamChannelHeader` is rendered by `StreamChannelInfo`. Pass a `textStyle` to it via a custom `subtitle` to change the text appearance:

```dart
StreamChannelHeader(
  subtitle: StreamChannelInfo(
    channel: StreamChannel.of(context).channel,
    textStyle: const TextStyle(
      color: Colors.grey,
      fontStyle: FontStyle.italic,
    ),
  ),
)
```

### Reading the typing state

Typing state is available from the `Channel` object provided by `StreamChannel`:

```dart
final typingUsers = StreamChannel.of(context).channel.typingEvents.keys.toList();
```

`typingEvents` is a `Map<User, Event>` of members currently composing a message (excluding the current user). Use `.keys.toList()` to get a `List<User>`.

For reactive updates, listen to the stream instead:

```dart
StreamBuilder<Map<User, Event>>(
  stream: StreamChannel.of(context).channel.typingEventsStream,
  builder: (context, snapshot) {
    final typingUsers = snapshot.data?.keys.toList() ?? [];
    if (typingUsers.isEmpty) return const SizedBox.shrink();
    final names = typingUsers.map((u) => u.name).join(', ');
    return Text('$names is typing…');
  },
)
```

### Controlling the typing event from the composer

`StreamMessageComposer` automatically sends start-typing and stop-typing events as the user types. If you build a fully custom composer, send these events manually using the channel API.

There are two approaches:

**`channel.keyStroke()`** — call this on every keypress. The SDK sends a `typing.start` event and then automatically schedules a `typing.stop` event after a debounce period. This is the recommended approach for most custom composers:

```dart
TextField(
  onChanged: (_) => channel.keyStroke(),
)
```

**`channel.startTyping()` / `channel.stopTyping()`** — send raw `typing.start` and `typing.stop` events directly, giving you full manual control. Use these only when you need to drive the typing lifecycle yourself (for example, a voice input that starts and stops on button press):

```dart
// When the user begins composing
await channel.startTyping();

// When the user finishes or cancels
await channel.stopTyping();
```

For most cases, `keyStroke()` is the simpler choice because the SDK handles the `typing.stop` automatically.


---

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

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