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;
  • 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 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 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. 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
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.

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 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 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.

Settings

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

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