# Message Composer

Every channel and thread has a `messageComposer` instance. It provides reactive state for the message being composed (for example, attachment upload state). Use `channel.sendMessage` if you don't need the `messageComposer`.

## Reading

```js label="JavaScript"
const { messageComposer } = channel;

// Typed text, mentions and the active command
const { text, mentions, command } =
  messageComposer.textComposer.state.getLatestValue();

// Attachments
const { attachments } =
  messageComposer.attachmentManager.state.getLatestValue();

// Quoted or edited message
const { quotedMessage, editedMessage } = messageComposer.state.getLatestValue();
```

Subscribe to render changes:

```js label="JavaScript"
const unsubscribeText =
  messageComposer.textComposer.state.subscribeWithSelector(
    (state) => ({ text: state.text }),
    ({ text }) => renderInput(text),
  );

const unsubscribeAttachments =
  messageComposer.attachmentManager.state.subscribeWithSelector(
    (state) => ({ attachments: state.attachments }),
    ({ attachments }) => renderAttachmentPreviews(attachments),
  );
```

## Send message

Send the composed message with `send()`. It never throws: a failed message stays in the message list marked `failed`, and the error is reported to `client.notifications`.

```js label="JavaScript"
// Usually called from your input's change handler
messageComposer.textComposer.setText("Hello!");

// "sent", "nothing-to-send" (the composer keeps its content) or "failed"
const result = await messageComposer.send();
```

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/javascript/state-composer/](https://getstream.io/chat/docs/javascript/state-composer/).