# Text

The text composer holds what the user types into a message: the text, the cursor position, the mentions and the active command. Every message composer has one, `messageComposer.textComposer`.

## What it holds

The text composer's state is in `textComposer.state`. These getters read its current values:

- `textComposer.text`: the text;
- `textComposer.selection`: the cursor position, or the selected range, as `{ start, end }`;
- `textComposer.textIsEmpty`: whether the text is empty, only whitespace, or only an empty formatting mark such as `**`;
- `textComposer.mentions`: the mentions in the text: users, roles, user groups, `@channel` and `@here`;
- `textComposer.command`: the active command, or `null`. See [Commands](https://getstream.io/chat/docs/sdk/react-native/state/writing-messages/commands/);
- `textComposer.suggestions`: the open suggestions, if any.

## Changing the text

Some calls pass the text composer's state through the **text middleware**: a pipeline of functions that runs in order. Each function can change the state or pass it on unchanged, and it can stop the pipeline. The built-in functions find mentions and commands, and you can add your own, as [Composer middleware](https://getstream.io/chat/docs/sdk/react-native/state/writing-messages/composer-middleware/) explains. The last column says which middleware handler a call runs, if any.

What a text input needs, and the call for each:

| To...                                                       | Call                                                    | What happens                                                                                                                                                                                                  | Text middleware          |
| ----------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| handle typing or deleting                                   | `TextComposer.handleChange({ text, selection })`        | Updates the text and cursor. The built-in middleware finds mentions and commands and opens [suggestions](https://getstream.io/chat/docs/sdk/react-native/state/writing-messages/suggestions/) for them. Reports typing, as below. | `onChange`               |
| insert pasted text, or text such as an emoji, at the cursor | `TextComposer.insertText({ text, selection })`          | Replaces the text in `selection`, or inserts at the cursor when `selection` is left out, then continues as `TextComposer.handleChange()`. Windows line endings become `\n`.                                   | `onChange`               |
| format the selection, such as making it bold                | `TextComposer.wrapSelection({ head, tail, selection })` | Puts `head` before and `tail` after the text in `selection`, or the current selection when `selection` is left out, and keeps it selected.                                                                    | none                     |
| move the cursor                                             | `TextComposer.setSelection(selection)`                  | Updates the cursor position that `TextComposer.insertText()` and `TextComposer.wrapSelection()` use.                                                                                                          | none                     |
| apply a suggestion the user picked                          | `TextComposer.handleSelect(suggestion)`                 | Replaces the typed trigger with the mention or command. See [Suggestions](https://getstream.io/chat/docs/sdk/react-native/state/writing-messages/suggestions/).                                                                   | `onSuggestionItemSelect` |
| set the text from code                                      | `TextComposer.setText(text)`                            | Replaces the text. Mentions, commands and the cursor stay as they were, and no suggestions open.                                                                                                              | none                     |

```ts
const { textComposer } = channel.messageComposer;

await textComposer.handleChange({
  selection: { end: 5, start: 5 },
  text: "Hello",
});
```

The SDK's `AutoCompleteInput` is the text input of the composer. It follows `textComposer.state` for the text and the active command, and it calls `TextComposer.handleChange()` with the latest text and selection, one task after a change, because iOS and Android report a change of text and a change of cursor in a different order. It also calls `TextComposer.setSelection()` when the cursor moves. A picked suggestion goes through `TextComposer.handleSelect()`.

Files the user picks or takes aren't text: they go to the [attachment manager](https://getstream.io/chat/docs/sdk/react-native/state/writing-messages/attachments/).

## Sending the text

When the message is built, the text goes into the message's `text` field, and the mentions go into `mentioned_users`, `mentioned_roles`, `mentioned_group_ids`, `mentioned_channel` and `mentioned_here`. A mention is sent only while its `@` name is still in the text, so a mention the user deleted from the text isn't sent.

A [draft](https://getstream.io/chat/docs/sdk/react-native/state/writing-messages/message-composer/#drafts) saves the text and its mentions too. When a draft or a message to edit is loaded into the composer, its text and mentions come back.

## Typing events

While the `publishTypingEvents` [setting](#settings) is on, which is the default, each change that leaves text in the composer reports a keystroke to the channel, which sends the typing events. A send stops them. See [Typing indicators](https://getstream.io/chat/docs/sdk/react-native/features/messaging/typing-indicators/).

## Settings

Set them for every composer in `client.config`, under `messageComposer.text`:

```ts
client.config.set({
  messageComposer: {
    text: { maxLengthOnEdit: 2_000, publishTypingEvents: false },
  },
});
```

To change a setting for one composer only, set it on that composer's text composer, for example `channel.messageComposer.textComposer.publishTypingEvents = false`.

| Setting               | Default | What it does                                                                                                                                                                                            |
| --------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`             | `true`  | `false` turns off text input: changes, inserts and selection are ignored, and the SDK's input isn't editable.                                                                                           |
| `defaultValue`        | none    | The text the composer holds when it starts without a message, and again after it's cleared.                                                                                                             |
| `maxLengthOnEdit`     | none    | Cuts the text while the user types or pastes.                                                                                                                                                           |
| `maxLengthOnSend`     | none    | Stops a longer message: `MessageComposer.send()` returns `'nothing-to-send'`, and no notification is published. A draft is cut to this length instead. The SDK's input also uses it as its `maxLength`. |
| `publishTypingEvents` | `true`  | Reports typing, as above.                                                                                                                                                                               |

The channel type's `max_message_length` caps both lengths. A composer that sets neither takes the server's limit.

## Used in

- [Mentions](https://getstream.io/chat/docs/sdk/react-native/features/messaging/mentions/)
- [Typing indicators](https://getstream.io/chat/docs/sdk/react-native/features/messaging/typing-indicators/)
- [Commands and Giphy](https://getstream.io/chat/docs/sdk/react-native/features/rich-content/commands-and-giphy/)

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/state/writing-messages/text/](https://getstream.io/chat/docs/sdk/react-native/state/writing-messages/text/).