# Channel Header

This example shows how to use a custom `ChannelHeader`. Unlike most components that are overridden via props, you can just render your custom header in place of the default.

## Best Practices

- Keep header UI lightweight to avoid re-render overhead.
- Pull channel data from `ChannelStateContext` via `useChannelStateContext` instead of duplicating state.
- Use `TypingIndicator` thoughtfully to avoid noisy headers.
- Remove the default typing indicator if you render a custom one.
- Preserve accessibility for channel title and controls.

### Implementation

The default header displays the channel name, member count, and online count. In this example, we render the name and add a typing indicator below. Because the custom header is a child of `Channel`, it can access `channel` via `ChannelStateContext` and `useChannelStateContext`.

```tsx
const CustomChannelHeader = (props: ChannelHeaderProps) => {
  const { title } = props;

  const { channel } = useChannelStateContext();
  const { name } = channel.data || {};

  return <div>{title || name}</div>;
};
```

Next, add the typing indicator to the header and remove the default one in `MessageList` by overriding it with a null component.

```tsx
const CustomChannelHeader = (props: ChannelHeaderProps) => {
    const { title } = props;

    const { channel } = useChannelStateContext();
    const { name } = channel.data || {};

    return (
        <>
            <div>{title || name}</div>
            <TypingIndicator />
        </>
    )
}

<Channel TypingIndicator={() => null}>
```

You can render additional header details by pulling more data from `channel`. For this demo, we’ll add some basic styling.

```css
.header-title {
  padding: 5px 7px;
}

.header-pound {
  color: #006cff;
  font-weight: 800;
  padding-right: 2px;
}
```

```tsx
const CustomChannelHeader = (props: ChannelHeaderProps) => {
  const { title } = props;

  const { channel } = useChannelStateContext();
  const { name } = channel.data || {};

  return (
    <div className="str-chat__header-livestream">
      <div>
        <div className="header-item">
          <span className="header-pound">#</span>
          {title || name}
        </div>
        <TypingIndicator />
      </div>
    </div>
  );
};
```

### The Final Code

Finally, render the custom header where the default would normally appear.

```css
.header-title {
  padding: 5px 7px;
}

.header-pound {
  color: #006cff;
  font-weight: 800;
  padding-right: 2px;
}
```

```tsx
const CustomChannelHeader = (props: ChannelHeaderProps) => {
  const { title } = props;

  const { channel } = useChannelStateContext();
  const { name } = channel.data || {};

  return (
    <div className="str-chat__header-livestream">
      <div>
        <div className="header-item">
          <span className="header-pound">#</span>
          {title || name}
        </div>
        <TypingIndicator />
      </div>
    </div>
  );
};
```

```tsx
const App = () => (
  <Chat client={chatClient}>
    <ChannelList />
    <Channel TypingIndicator={() => null}>
      <Window>
        <CustomChannelHeader />
        <MessageList />
        <MessageInput />
      </Window>
      <Thread />
    </Channel>
  </Chat>
);
```

## The Result

![Custom ChannelHeader in Chat](@chat-sdk/react/v13/_assets/CustomChannelHeader.png)


---

This page was last updated at 2026-04-21T09:53:42.244Z.

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