# Quoted replies

> **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/).

## What users get

A quoted reply answers a specific message without leaving the conversation: the reply carries a copy of the message it answers.

- **Quoting.** **Reply** in a message's menu, or swiping the message sideways, shows the message above the composer's input, titled "Reply to Ben", or "You" for the user's own message. The close button on the preview removes the quote. With a screen reader on, **Reply** also moves the focus to the input.
- **The sent reply.** The quoted message appears at the top of the reply's bubble, with its author, its text, and a thumbnail or icon for its attachments.
- **Jumping.** Tapping the quoted message jumps to the original in the list and highlights it, loading older messages when it isn't loaded.
- **Staying current.** If the quoted message is edited while the user is writing, the preview updates. If it's deleted, the quote is removed.

<table>
  <tr>
  <td align='center' width='50%'>

![A sent reply with the quoted message and its author at the top of the bubble on iOS](https://getstream.io/docs-assets/images/550103c3602a.png)

  </td>
  <td align='center' width='50%'>

![A sent reply with the quoted message and its author at the top of the bubble on Android](https://getstream.io/docs-assets/images/f6de5fd33e8e.png)

  </td>
  </tr>
</table>

## How it works across the layers

The user wants to answer Ben's question from earlier in "Design":

1. They pick **Reply** on Ben's message. The action calls `setQuotedMessage(message)` from `useMessageComposerAPIContext()`, which calls `MessageComposer.setQuotedMessage(message)` on the composer they type in: the channel's, or the thread's inside a `Thread`. Swiping the message does the same through `setQuotedMessage` from the message context.
2. The composer keeps the message in its state as `quotedMessage`. `MessageInputHeaderView` reads it and renders `Reply` with `mode='reply'` above the input.
3. The user sends their reply. The composer adds `quoted_message_id` to the request, and a copy of the quoted message to the local message, so the reply shows the quote while it's sending.
4. In the message list, `MessageContent` renders `Reply` for `message.quoted_message`. Tapping it calls `goToMessage(id)`, which calls `MessagePaginator.jumpToMessage()` on the list's message paginator.

While a message is quoted, commands of the moderation set are disabled in the composer. A draft keeps its quote, and restoring the draft brings it back. Removing the quote is `MessageComposer.setQuotedMessage(null)`. While the user edits a message, the composer shows the edit preview instead of the quote.

The composer's state and its parts are on [Message composer](https://getstream.io/chat/docs/sdk/react-native/v10/state/writing-messages/message-composer/), and the composer's previews on [Message composer UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-composer-ui/). How the list jumps to a message is on [Message paginators](https://getstream.io/chat/docs/sdk/react-native/v10/state/loading-data/message-paginators/).

## Turning it on or off

Quoted replies are always available. Three things decide who can use them, and where:

- **The `quote-message` capability.** Without it, the message menu leaves out **Reply**. The server derives it from the user's role and the channel type's settings, which include `quotes`.
- **Threads.** The default menu leaves out **Reply** inside a `Thread`, and on a thread reply shown in the channel.
- **Swiping.** Swipe to reply is on by default, on every message except a deleted one, and doesn't check the capability. Turn it off with `enableSwipeToReply={false}` on `Channel` and `Thread`.

To hide quoting from users who have the capability, pass `overrideOwnCapabilities={{ quoteMessage: false }}` and `enableSwipeToReply={false}`.

## Customizing

### Quoting from your own control

Any component inside a `Channel` or `Thread` can quote a message through the composer:

```tsx
import { Pressable, Text } from "react-native";
import type { LocalMessage } from "stream-chat";
import { useMessageComposer } from "stream-chat-react-native";

export const QuoteButton = ({ message }: { message: LocalMessage }) => {
  const composer = useMessageComposer();

  return (
    <Pressable onPress={() => composer.setQuotedMessage(message)}>
      <Text>Quote</Text>
    </Pressable>
  );
};
```

To put it in the message menu, add an action to the message actions; see [Message actions](https://getstream.io/chat/docs/sdk/react-native/v10/features/messaging/message-actions/#customizing).

### Changing the swipe

- `customMessageSwipeAction` on `Channel` and `Thread` replaces what a swipe does. It receives `{ channel, message }`.
- `messageSwipeToReplyHitSlop` sets the area that starts the swipe.
- `MessageSwipeContent` is the override key for what shows beside the message while it's swiped, a reply icon by default.

### Replacing the preview in the composer

`Reply` is an override key. It renders the composer's preview, with `mode='reply'` for a quote and `mode='edit'` for an edit, and the quote inside a sent message. Only the composer's preview receives `onDismiss`. This replacement keeps the default everywhere except the composer's quote:

```tsx
import { Pressable, StyleSheet, Text, View } from "react-native";
import type { MessageComposerState } from "stream-chat";
import type { ReplyProps } from "stream-chat-react-native";
import {
  Reply,
  useMessageComposer,
  useStateStore,
  WithComponents,
} from "stream-chat-react-native";

const quoteSelector = (state: MessageComposerState) => ({
  quotedMessage: state.quotedMessage,
});

const CompactReply = (props: ReplyProps) => {
  const composer = useMessageComposer();
  const { quotedMessage } = useStateStore(composer.state, quoteSelector);

  if (props.mode !== "reply" || !props.onDismiss) return <Reply {...props} />;
  if (!quotedMessage) return null;

  return (
    <View style={styles.row}>
      <Text numberOfLines={1} style={styles.title}>
        Replying to {quotedMessage.user?.name ?? "a message"}
      </Text>
      <Pressable onPress={props.onDismiss}>
        <Text>Cancel</Text>
      </Pressable>
    </View>
  );
};

const styles = StyleSheet.create({
  row: { flexDirection: "row", gap: 8, padding: 8 },
  title: { flex: 1 },
});

export const App = () => (
  <WithComponents overrides={{ Reply: CompactReply }}>
    {/* the rest of the app */}
  </WithComponents>
);
```

### Replacing the quote in a message

Inside a message, a `Reply` replacement reads the message from `useMessageContext()`. Its `quoted_message` is the quote, and `goToMessage` jumps to the original in the list the message is in, the channel's or the thread's:

```tsx
import { Pressable, Text } from "react-native";
import type { ReplyProps } from "stream-chat-react-native";
import {
  Reply,
  useMessageContext,
  WithComponents,
} from "stream-chat-react-native";

const QuoteLine = (props: ReplyProps) => {
  const { goToMessage, message } = useMessageContext();
  const quoted = message?.quoted_message;

  // Outside a message, this is the composer's preview: keep the default.
  if (!message) return <Reply {...props} />;
  if (!quoted) return null;

  return (
    <Pressable onPress={() => goToMessage?.(quoted.id)}>
      <Text numberOfLines={1}>
        {quoted.user?.name}: {quoted.text}
      </Text>
    </Pressable>
  );
};

export const App = () => (
  <WithComponents overrides={{ Reply: QuoteLine }}>
    {/* the rest of the app */}
  </WithComponents>
);
```

The default bubble makes the quote pressable around `Reply`, so a replacement that renders its own `Pressable` handles the tap first. The jump itself is explained on [Message paginators](https://getstream.io/chat/docs/sdk/react-native/v10/state/loading-data/message-paginators/).

## Reference

- State: [Message composer](https://getstream.io/chat/docs/sdk/react-native/v10/state/writing-messages/message-composer/) and the [MessageComposer API](https://getstream.io/chat/docs/sdk/react-native/v10/reference/state/messagecomposer-api/).
- UI: [Message composer UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-composer-ui/), [Message list UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-list-ui/) and [Overriding components](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overriding-components/).
- Props: [Channel](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel/channel/), [Composer UI components](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message-composer/composer-ui-components/) and [Message UI components](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message/message-ui-components/).
- Hooks: [Composer hooks](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/composer-hooks/).

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v10/features/messaging/quoted-replies/](https://getstream.io/chat/docs/sdk/react-native/v10/features/messaging/quoted-replies/).