---
id: input_ui
sidebar_position: 3
title: Message Input UI
---

## How-to Guide for Building a Custom Message Input

The React Chat component library provides a highly customizable `MessageInput` component. We'll outline the various ways in which you
can customize the look and behavior of this component, ranging from simple style changes, all the way to creating a completely
new input with custom logic.

### Styling

The default [Input UI](../../components/message-input-components/input-ui.mdx) component comes with predefined styles and CSS classes. The easiest way
to customize styling is to write your own CSS and override the default values. To get a sense of all the classes and styles
applied to the `MessageInput` and its child components, you can either inspect the DOM inside your browser.

For example, here's how you can override the styles for the underlying `textarea` and make its background light blue:

```css
.str-chat .str-chat__textarea > textarea {
  background-color: #99ccff;
}
```

### Customize Functionality

The `MessageInput` component supports a variety of props that let you customize its behavior in various ways.
You can utilize props to change basic behaviors of the underlying `textarea` element (ex: the `grow` prop lets you specify
whether the input field should automatically increase in height when the message wraps the input), as well as override
functions and more complex and logic-based parts of the component (ex: the `doImageUploadRequest` prop lets you supply a custom
function that handles the uploading of image attachments).

:::note
For a complete overview of props, take a look at the [MessageInput props](../../components/message-input-components/message-input.mdx#props) section.
:::

### Override UI Components

You can override the UI components rendered inside the `MessageInput` via `Channel` props. These are then injected into the `ComponentContext`, and in turn are consumed by the
`MessageInput`.

Here's an example of overriding the default `EmojiIcon` component:

```jsx
const CustomEmojiIcon = () => {
  const { t } = useTranslationContext();

  return (
    <div>
      <img src='icon.svg' alt={t('Open emoji picker')} />
    </div>
  );
};

<Chat client={client}>
  <Channel channel={channel} EmojiIcon={CustomEmojiIcon}>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>;
```

### Custom Triggers

The `MessageInput` component supports autocomplete triggers. When you type a special character (by default: `@` for mentions,
`:` for emoji, `/` for commands), a suggestion list pops up and auto-completes results based on the input text. The default
behavior of these triggers can be extended and/or overridden. Meaning, you can add your own custom trigger, or modify the
behavior of the default triggers.

The `Channel` component exposes a `TriggerProvider` prop, which defaults to the [`DefaultTriggerProvider`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageInput/DefaultTriggerProvider.tsx)
component. This component injects the approved set of triggers into the `autocompleteTriggers`
value of the `MessageInputContext`. This value is consumed by the `ChatAutoComplete` component and its children to ensure
proper trigger functionality. By injecting a custom `TriggerProvider` component, you can adjust the behavior of any of these
triggers.

Here's an example of a custom `TriggerProvider` that overrides the default values with the `#` character:

```jsx
import React from 'react';
import { MessageInputContextProvider, useMessageInputContext } from 'stream-chat-react';

const options = ['some', 'thing', 'that', 'totally', 'works'];

const CustomSuggestionItem = (props) => <div>{props.entity.name}</div>;

const customTrigger = {
  component: CustomSuggestionItem,
  dataProvider: (query, _, onReady) => {
    const filteredOptions = options
      .filter((option) => option.includes(query))
      .map((option) => ({ name: option }));
    onReady(filteredOptions, query);
  },
  output: (entity) => ({
    caretPosition: 'next',
    key: entity.name,
    text: entity.name,
  }),
};

const customTriggers = {
  '#': customTrigger,
};

export const CustomTriggerProvider = ({ children }) => {
  const currentContextValue = useMessageInputContext();

  const updatedContextValue = {
    ...currentContextValue,
    autocompleteTriggers: customTriggers,
  };

  return (
    <MessageInputContextProvider value={updatedContextValue}>
      {children}
    </MessageInputContextProvider>
  );
};
```

The `CustomTriggerProvider` component is then added as a prop onto `Channel` to override the default trigger behavior.

```jsx
<Chat client={client}>
  <Channel channel={channel} TriggerProvider={CustomTriggerProvider}>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>
```

### Building the Input UI

The `MessageInput` component wraps and provides all the stateful logic needed to build your own Input UI component.
Both `Channel` and `MessageInput` accept an `Input` prop, which lets you pass in your own UI component that consumes the
`MessageInputContext` and handles the input's display.

:::note
If an `Input` prop is not provided, `MessageInput` renders [`MessageInputFlat`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageInput/MessageInputFlat.tsx)
by default.
:::

We provide a `useMessageInputContext` custom hook, which lets you access all the stateful data and functionality needed
to create your own custom Input UI component.

:::tip
Use `MessageInputFlat` as a guide to help you build your own custom Input UI component.
:::

The below example shows how to build a simple Input UI component, which calls the `useMessageInputContext` hook
and use its return values to build functionality:

```jsx
import {
  ChatAutoComplete,
  EmojiIconLarge,
  EmojiPicker,
  SendButton,
  Tooltip,
  useMessageInputContext,
  useTranslationContext,
} from 'stream-chat-react';

export const CustomMessageInput = () => {
  const { t } = useTranslationContext();

  const {
    closeEmojiPicker,
    emojiPickerIsOpen,
    handleEmojiKeyDown,
    handleSubmit,
    openEmojiPicker,
  } = useMessageInputContext();

  return (
    <div className='str-chat__input-flat str-chat__input-flat--send-button-active'>
      <div className='str-chat__input-flat-wrapper'>
        <div className='str-chat__input-flat--textarea-wrapper'>
          <ChatAutoComplete />
          <div className='str-chat__emojiselect-wrapper'>
            <Tooltip>
              {emojiPickerIsOpen ? t('Close emoji picker') : t('Open emoji picker')}
            </Tooltip>
            <span
              className='str-chat__input-flat-emojiselect'
              onClick={emojiPickerIsOpen ? closeEmojiPicker : openEmojiPicker}
              onKeyDown={handleEmojiKeyDown}
              role='button'
              tabIndex={0}
            >
              <EmojiIconLarge />
            </span>
          </div>
          <EmojiPicker />
        </div>
        <SendButton sendMessage={handleSubmit} />
      </div>
    </div>
  );
};
```

Once you've created your custom input component, you render it by adding the `Input` prop to either the `Channel` or `MessageInput`
component. Adding onto `Channel` will store the component in the `ComponentContext`, whereas adding onto `MessageInput` will
override any context value.

```jsx
<Chat client={client}>
  <Channel channel={channel} Input={CustomMessageInput}>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>
```
