# Typing Indicator

This example shows how to build a custom message-list `TypingIndicator` based on the current v14 prop contract.

## Best Practices

- Respect `typing_events` in channel config so you do not show typing UI when the feature is disabled.
- Filter out the current user from typing results.
- Keep the message-list typing indicator and header typing indicator separate.
- Preserve the `scrollToBottom` behavior if you want the list to stay pinned while typing.
- Summarize or cap typing users in busy channels.

## Create The Component

The message-list `TypingIndicator` now receives `scrollToBottom`, optional `isMessageListScrolledToBottom`, and `threadList`.

```tsx
import { useEffect } from "react";
import {
  type TypingIndicatorProps,
  useChannelStateContext,
  useChatContext,
  useTypingContext,
} from "stream-chat-react";

export const CustomTypingIndicator = ({
  isMessageListScrolledToBottom = true,
  scrollToBottom,
  threadList,
}: TypingIndicatorProps) => {
  const { channelConfig, thread } = useChannelStateContext();
  const { client } = useChatContext();
  const { typing = {} } = useTypingContext();

  const typingUsers = Object.values(typing).filter(({ parent_id, user }) => {
    if (user?.id === client.user?.id) return false;
    if (threadList) return parent_id === thread?.id;
    return !parent_id;
  });

  useEffect(() => {
    if (typingUsers.length > 0 && isMessageListScrolledToBottom) {
      scrollToBottom();
    }
  }, [isMessageListScrolledToBottom, scrollToBottom, typingUsers.length]);

  if (channelConfig?.typing_events === false) return null;
  if (!typingUsers.length || !isMessageListScrolledToBottom) return null;

  return (
    <div className="custom-typing-indicator">
      <span>{typingUsers.map(({ user }) => user?.name).join(", ")}</span>
      <span className="custom-typing-indicator__dots">...</span>
    </div>
  );
};
```

```css
.custom-typing-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #6b7280;
}
```

## Register The Override

`TypingIndicator` is a `ComponentContext` override in v14, so register it with `WithComponents`:

```tsx
import {
  Channel,
  MessageComposer,
  MessageList,
  Thread,
  WithComponents,
} from "stream-chat-react";

const App = () => (
  <WithComponents overrides={{ TypingIndicator: CustomTypingIndicator }}>
    <Channel>
      <MessageList />
      <MessageComposer />
      <Thread />
    </Channel>
  </WithComponents>
);
```

## Header Typing Indicators

If you want typing state in a custom `ChannelHeader` or `ThreadHeader`, render `TypingIndicatorHeader` there instead of reusing the message-list `TypingIndicator`.


---

This page was last updated at 2026-05-22T16:32:14.243Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/guides/customization/typing-indicator/](https://getstream.io/chat/docs/sdk/react/guides/customization/typing-indicator/).