# Message Composer UI

The message composer is a primary interaction surface in chat, so custom layouts should preserve the SDK’s composer behavior for uploads, autocomplete, quoted messages, and submission.

## Best Practices

- Compose custom input UI from exported building blocks instead of duplicating composer state.
- Keep `TextareaComposer` central so autocomplete and slash commands still work.
- Read cooldown through `useCooldownRemaining()` or `CooldownTimer`, not from `MessageComposerContext`.
- Render custom input UI by scoping `WithComponents overrides={{ MessageComposerUI: ... }}` around the target composer subtree.
- Decide whether your custom layout should match the default command-selected state, where the attachment selector and extra actions collapse while `CommandChip` is active.
- Test quoted-message, attachment, link-preview, and voice-recording states together.

You can compose a custom input from the exported pieces used by `MessageComposerUI`:

```tsx
import {
  AttachmentPreviewList,
  CooldownTimer,
  LinkPreviewList,
  MessageComposerActions,
  QuotedMessagePreview,
  SendButton,
  SimpleAttachmentSelector,
  TextareaComposer,
  VoiceRecordingPreviewSlot,
  useCooldownRemaining,
  useMessageComposerContext,
} from "stream-chat-react";

const SendButtonWithCooldown = () => {
  const cooldownRemaining = useCooldownRemaining();
  const { handleSubmit } = useMessageComposerContext();

  return cooldownRemaining ? (
    <CooldownTimer />
  ) : (
    <SendButton sendMessage={handleSubmit} />
  );
};

const CustomMessageComposer = () => (
  <div className="message-input">
    <div className="left-container">
      <SimpleAttachmentSelector />
    </div>
    <div className="central-container">
      <QuotedMessagePreview />
      <VoiceRecordingPreviewSlot />
      <AttachmentPreviewList />
      <LinkPreviewList />
      <TextareaComposer />
    </div>
    <div className="right-container">
      <MessageComposerActions />
      <SendButtonWithCooldown />
    </div>
  </div>
);
```

If you want the default slash-command layout too, keep the `str-chat__message-composer*` wrappers and toggle the same `str-chat__message-composer--command-active` class when a command is selected. The built-in composer uses that state to collapse the attachment selector and additional action buttons while keeping `CommandChip` visible next to the textarea.

Render the custom layout through `MessageComposer` so the SDK still provides the required composer context:

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

const App = () => (
  <Channel>
    <Window>
      <ChannelHeader />
      <MessageList />
      <WithComponents overrides={{ MessageComposerUI: CustomMessageComposer }}>
        <MessageComposer />
      </WithComponents>
    </Window>
    <Thread />
  </Channel>
);
```


---

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

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