# MessageInputContext

> **Info:** This is release candidate documentation for **Stream Chat React Native SDK v10**. For the latest stable version, see the [latest version (v9)](https://getstream.io/chat/docs/sdk/react-native/).

`MessageInputContext` holds the composer settings set on `Channel` or `Thread`, and the functions the composer UI calls: send, the pickers, the attachment picker and the voice recorder. `Channel` and `Thread` provide it to everything they render, and every part of the composer UI reads it with `useMessageInputContext()`. It holds UI settings and actions, not the message: the text, the attachments and the rest are in the composer's stores, which [Message composer UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-composer-ui/#what-each-part-reads) maps to the parts that read them.

## Best practices

- Read the message being written from the composer, with `useMessageComposer()` and `useStateStore`, not from this context.
- Send with `sendMessage()` from this context, so your controls send, edit and check links the way the default send button does.
- Set the values on `Channel` and `Thread`. The context is memoized and gets a new value only when `hasCommands` changes or the poll creation dialog opens or closes, so a prop changed after mount, such as `audioRecordingEnabled`, doesn't reach it. Remount the `Channel` or `Thread`, for example with a `key`, to apply it.
- Read the cooldown with [`useCooldownRemaining`](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/channel-and-thread-hooks/#usecooldownremaining). It isn't in this context.
- Render components that read it inside a `Channel` or a `Thread`. `useMessageInputContext()` throws outside both.

## Basic usage

This button sits next to the composer and opens the attachment picker on the photo grid:

```tsx title="src/AddPhotosButton.tsx"
import { Pressable, Text } from "react-native";
import { useMessageInputContext } from "stream-chat-react-native";

export const AddPhotosButton = () => {
  const { hasImagePicker, openAttachmentPicker } = useMessageInputContext();

  if (!hasImagePicker) return null;

  return (
    <Pressable onPress={openAttachmentPicker}>
      <Text>Add photos</Text>
    </Pressable>
  );
};
```

`openAttachmentPicker()` closes the keyboard, selects the photo grid and opens the sheet. It does nothing when `shouldRenderAttachmentPicker` is `false` on `Channel` or `Thread`.

## Values

Each `Channel` and `Thread` creates its own `audioRecorderManager`, `inputBoxRef` and `messageInputHeightStore`, so a channel screen and a thread screen don't share a recorder or an input.

| Value                                | Type                                                                                                    | Description                                                                                                                                                                                                                                                                                                                                                                                    |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sendMessage`                        | `() => Promise<void>`                                                                                   | Sends the composition with `MessageComposer.send()`, or saves the edit with `MessageComposer.update()` while a message is being edited. Saving the edit of a bounced message sends it again as a new message. It clears the input first, and puts the text back when there was nothing to send. When the text has a link and the user lacks `send-links`, it shows an alert and sends nothing. |
| `inputBoxRef`                        | `React.RefObject<InputBoxRef \| null>`                                                                  | The text input. Besides the `TextInput` methods, such as `focus()`, it has `clearState()` and `restoreState(text)`, which set the input's text without changing the composer.                                                                                                                                                                                                                  |
| `setInputBoxRef`                     | `Ref<InputBoxRef> \| undefined`                                                                         | The ref callback the text input uses. It fills `inputBoxRef` and calls `setInputRef`.                                                                                                                                                                                                                                                                                                          |
| `setInputRef`                        | `(ref: TextInputRef \| null) => void`                                                                   | The `Channel` or `Thread` prop. Receives the text input, and `null` when it unmounts.                                                                                                                                                                                                                                                                                                          |
| `additionalTextInputProps`           | `TextInputProps`                                                                                        | The `Channel` or `Thread` prop. `MessageComposer` spreads it onto the `TextInput`.                                                                                                                                                                                                                                                                                                             |
| `messageInputFloating`               | `boolean`                                                                                               | The `Channel` or `Thread` prop, `false` by default. The composer floats over the message list, and the list leaves room for it.                                                                                                                                                                                                                                                                |
| `messageInputHeightStore`            | `MessageInputHeightStore`                                                                               | A store whose `store` holds the composer's measured `height`. The message list reads it to leave room for a floating composer.                                                                                                                                                                                                                                                                 |
| `openAttachmentPicker`               | `() => void`                                                                                            | Closes the keyboard, selects the photo grid and opens the attachment picker. Does nothing when `shouldRenderAttachmentPicker` is `false`.                                                                                                                                                                                                                                                      |
| `closeAttachmentPicker`              | `() => void`                                                                                            | Clears the selected source and closes the attachment picker.                                                                                                                                                                                                                                                                                                                                   |
| `focusInputOnPickerClose`            | `boolean`                                                                                               | The `Channel` or `Thread` prop, `true` by default. When the user presses the attach button while the picker is open, `true` focuses the input, which opens the keyboard and closes the picker, and `false` closes the picker without focusing.                                                                                                                                                 |
| `handleAttachButtonPress`            | `() => void`                                                                                            | The `Channel` or `Thread` prop. Replaces what the attach button does, which is to open or close the picker.                                                                                                                                                                                                                                                                                    |
| `attachmentPickerBottomSheetHeight`  | `number`                                                                                                | The `Channel` or `Thread` prop: the height of the picker when open. `333` by default, or `72` when `disableAttachmentPicker` is `true`.                                                                                                                                                                                                                                                        |
| `attachmentSelectionBarHeight`       | `number`                                                                                                | The `Channel` or `Thread` prop, `72` by default. No component reads it.                                                                                                                                                                                                                                                                                                                        |
| `hasImagePicker`                     | `boolean`                                                                                               | The `Channel` or `Thread` prop. Whether the picker shows the photos button. By default, whether an image picker or a media library is installed.                                                                                                                                                                                                                                               |
| `hasCameraPicker`                    | `boolean`                                                                                               | The `Channel` or `Thread` prop. Whether the picker shows the camera button. By default, whether an image picker is installed.                                                                                                                                                                                                                                                                  |
| `hasFilePicker`                      | `boolean`                                                                                               | The `Channel` or `Thread` prop. Whether the picker shows the files button. By default, whether a document picker is installed.                                                                                                                                                                                                                                                                 |
| `hasCommands`                        | `boolean`                                                                                               | The `Channel` or `Thread` prop. Whether the picker shows the commands button. By default, whether the channel type has commands.                                                                                                                                                                                                                                                               |
| `pickAndUploadImageFromNativePicker` | `() => Promise<void>`                                                                                   | Opens the native image picker for as many images as the message has room for, and uploads the picked ones into the composer. Asks the user to open the settings when access was denied.                                                                                                                                                                                                        |
| `takeAndUploadImage`                 | `(mediaType?: MediaTypes) => Promise<{ askToOpenSettings?: boolean; canceled?: boolean } \| undefined>` | Opens the camera for a photo, a video or both (`"image"`, `"video"` or `"mixed"`), and uploads the result into the composer. Resolves to the camera's result, with `askToOpenSettings` when access was denied and `cancelled` when the user closed the camera (the type spells it `canceled`), or to `undefined` when the message has no room for another file.                                |
| `pickFile`                           | `() => Promise<void>`                                                                                   | Opens the system file picker and uploads the picked files into the composer. Does nothing without a document picker.                                                                                                                                                                                                                                                                           |
| `uploadNewFile`                      | `(file: File) => Promise<void>`                                                                         | Uploads a file into the composer through its attachment manager. It sets the file's type from its name when missing, and compresses images with `compressImageQuality` first. A file the upload rules block is removed from the composer.                                                                                                                                                      |
| `compressImageQuality`               | `number`                                                                                                | The `Channel` or `Thread` prop, from 0 to 1. Without it, picked images upload as they are, and photos the camera takes use the camera handler's own quality.                                                                                                                                                                                                                                   |
| `audioRecordingEnabled`              | `boolean`                                                                                               | The `Channel` or `Thread` prop, `false` by default. Whether the record button shows while the composer is empty.                                                                                                                                                                                                                                                                               |
| `audioRecordingSendOnComplete`       | `boolean`                                                                                               | The `Channel` or `Thread` prop, `false` by default. Whether a finished recording is sent at once, instead of waiting in the composer.                                                                                                                                                                                                                                                          |
| `asyncMessagesMinimumPressDuration`  | `number`                                                                                                | The `Channel` or `Thread` prop, `500` by default: how long, in milliseconds, the user holds the record button to start recording.                                                                                                                                                                                                                                                              |
| `asyncMessagesSlideToCancelDistance` | `number`                                                                                                | The `Channel` or `Thread` prop, `75` by default: how far, in points, the user slides to the left to cancel a recording. Releasing past half of it cancels.                                                                                                                                                                                                                                     |
| `asyncMessagesLockDistance`          | `number`                                                                                                | The `Channel` or `Thread` prop, `50` by default: how far, in points, the user slides up to lock a recording. Releasing past half of it locks.                                                                                                                                                                                                                                                  |
| `audioRecorderManager`               | `AudioRecorderManager`                                                                                  | The recorder. Its `state` store holds `status` (`"idle"`, `"recording"` or `"stopped"`), `duration` in milliseconds, `waveformData`, `micLocked`, `isStarting` and the `recording`.                                                                                                                                                                                                            |
| `startVoiceRecording`                | `() => Promise<boolean \| undefined>`                                                                   | Starts recording. Resolves to whether the microphone permission was granted.                                                                                                                                                                                                                                                                                                                   |
| `stopVoiceRecording`                 | `() => Promise<void>`                                                                                   | Stops recording and keeps the recording, for the preview.                                                                                                                                                                                                                                                                                                                                      |
| `deleteVoiceRecording`               | `() => Promise<void>`                                                                                   | Stops recording and throws the recording away.                                                                                                                                                                                                                                                                                                                                                 |
| `uploadVoiceRecording`               | `(sendOnComplete: boolean) => Promise<void>`                                                            | Stops recording and turns the recording into a `voiceRecording` attachment. With `true`, it adds the attachment and sends the message at once; with `false`, it uploads the attachment into the composer.                                                                                                                                                                                      |
| `openPollCreationDialog`             | `({ sendMessage }: Pick<LocalMessageInputContext, 'sendMessage'>) => void`                              | Called by the poll button of the picker. It calls the `Channel` or `Thread` prop of the same name with `{ sendMessage }` when you set one, and opens the default poll creation dialog otherwise.                                                                                                                                                                                               |
| `showPollCreationDialog`             | `boolean`                                                                                               | Whether the default poll creation dialog is open.                                                                                                                                                                                                                                                                                                                                              |
| `closePollCreationDialog`            | `() => void`                                                                                            | Closes the default poll creation dialog.                                                                                                                                                                                                                                                                                                                                                       |
| `createPollOptionGap`                | `number`                                                                                                | The `Channel` or `Thread` prop. The default `MessageComposer` doesn't pass it to the poll form, which uses `8` unless `MessageComposer` gets a `createPollOptionGap` prop of its own.                                                                                                                                                                                                          |

`MessageInputContextValue` is the type of the value, and `MessageInputContext` itself is exported, so `useContext(MessageInputContext)` returns the same as `useMessageInputContext()` without the check for a provider. `InputBoxRef`, `TextInputRef`, `File` and `LocalMessageInputContext` are exported types.

## MessageComposerAPIContext

`Channel` and `Thread` also provide `MessageComposerAPIContext`, with the functions that start and end an edit and set the quoted message. `useMessageComposerAPIContext()` reads it, and throws outside both.

| Value               | Type                                  | Description                                                                                                                                                                                                                                         |
| ------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `setEditingState`   | `(message?: LocalMessage) => void`    | Starts editing `message`: it takes the message's composer from `client.messageComposerCache`, or creates one, and loads the message into it. `useMessageComposer()` returns that composer until the edit ends. Without a message, it ends the edit. |
| `clearEditingState` | `() => void`                          | Ends the edit without saving it.                                                                                                                                                                                                                    |
| `setQuotedMessage`  | `MessageComposer['setQuotedMessage']` | Sets the quoted message of the composer `useMessageComposer()` returns, or clears it with `null`.                                                                                                                                                   |

An edit also ends when the edit composer's `editedMessage` is cleared, which saving the edit does. [Sending, editing and deleting](https://getstream.io/chat/docs/sdk/react-native/v10/features/messaging/sending-editing-and-deleting/) shows the edit flow.

## Examples

### Insert text and focus the input

A part that writes into the composer gets the composer from `useMessageComposer()` and the input from `inputBoxRef`. This leading view keeps the attach button and adds a greeting button:

```tsx title="src/LeadingViewWithGreeting.tsx"
import { Pressable, Text, View } from "react-native";
import {
  MessageComposerLeadingView,
  useMessageComposer,
  useMessageInputContext,
} from "stream-chat-react-native";

export const LeadingViewWithGreeting = () => {
  const { inputBoxRef } = useMessageInputContext();
  const { textComposer } = useMessageComposer();

  const greet = () => {
    textComposer.insertText({ text: "Hi there! " });
    inputBoxRef.current?.focus();
  };

  return (
    <View style={{ alignItems: "center", flexDirection: "row" }}>
      <MessageComposerLeadingView />
      <Pressable onPress={greet}>
        <Text>Greet</Text>
      </Pressable>
    </View>
  );
};
```

Register it as `MessageComposerLeadingView` with `WithComponents`. It renders the default view, so the attach button stays.

### Send from your own button

`sendMessage()` sends what the composer holds, or saves the edit. Pair it with `useMessageComposerHasSendableData()`, which the default send button uses to enable itself:

```tsx title="src/TextSendButton.tsx"
import { Pressable, Text } from "react-native";
import {
  useMessageComposerHasSendableData,
  useMessageInputContext,
} from "stream-chat-react-native";

export const TextSendButton = () => {
  const { sendMessage } = useMessageInputContext();
  const hasSendableData = useMessageComposerHasSendableData();

  return (
    <Pressable disabled={!hasSendableData} onPress={sendMessage}>
      <Text>Send</Text>
    </Pressable>
  );
};
```

Register it as `SendButton`. The default trailing view still shows the record button, the cooldown timer and the edit button in their cases, and your button otherwise.

## Hooks

- [`useMessageInputContext`](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/composer-hooks/#usemessageinputcontext) returns this context.
- [`useMessageComposerAPIContext`](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/composer-hooks/#usemessagecomposerapicontext) returns the edit and quote functions.
- [`useMessageComposer`](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/composer-hooks/#usemessagecomposer) returns the composer itself.
- [`useAudioRecorder`](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/composer-hooks/#useaudiorecorder) creates the recorder functions. `Channel` and `Thread` call it already.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message-composer/messageinputcontext/](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message-composer/messageinputcontext/).