diff --git a/docs.json b/docs.json
index 035cebab9..57c608122 100644
--- a/docs.json
+++ b/docs.json
@@ -33,7 +33,7 @@
{
"product": "Home",
"pages": [
- "index"
+ "index"
]
},
{
@@ -1208,6 +1208,7 @@
"ui-kit/react-native/guide-new-chat",
"ui-kit/react-native/guide-group-chat",
"ui-kit/react-native/guide-threaded-messages",
+ "ui-kit/react-native/guide-pin-and-save-messages",
"ui-kit/react-native/guide-search-messages",
"ui-kit/react-native/guide-message-privately",
"ui-kit/react-native/guide-block-unblock-user",
diff --git a/images/pin.png b/images/pin.png
new file mode 100644
index 000000000..56e141e60
Binary files /dev/null and b/images/pin.png differ
diff --git a/images/save.png b/images/save.png
new file mode 100644
index 000000000..ab78df01b
Binary files /dev/null and b/images/save.png differ
diff --git a/ui-kit/react-native/conversations.mdx b/ui-kit/react-native/conversations.mdx
index e2c86e498..9992eafb7 100644
--- a/ui-kit/react-native/conversations.mdx
+++ b/ui-kit/react-native/conversations.mdx
@@ -417,36 +417,15 @@ A pinned conversation sits at the top of the list. The pin is **private to the l
nobody else sees it — and it syncs to that user's other devices.
- **Off by default, and it needs a server flag that is not seeded.** Pin Conversation requires
+ **Pin Conversation needs a server flag that is not seeded.** It requires
`features.ux.conversations.pinned.enabled`, which ships enabled in no plan and must be mapped per
- app. Until then every attempt rejects with `ERR_FEATURE_NOT_ACCESSIBLE`. On top of that, the kit
- needs your own opt-in via `PinConversationConfig.enable(true)`.
+ app. Until then the option never renders, and a direct SDK call rejects with
+ `ERR_FEATURE_NOT_ACCESSIBLE`. The UI Kit reads that flag itself at login and on every reconnect —
+ there is no app code to write.
-
-
-```typescript
-import { PinConversationConfig } from "@cometchat/chat-uikit-react-native";
-
-// Once, at app start — defaults to off
-PinConversationConfig.enable(true);
-```
-
-
-
-
-```javascript
-import { PinConversationConfig } from "@cometchat/chat-uikit-react-native";
-
-PinConversationConfig.enable(true);
-```
-
-
-
-
-
`pinConversationOptionVisibility` (default `true`) hides the option on one particular list. It is
-**ANDed** with the global config, so the option renders only when both allow it.
+**ANDed** with the Dashboard flag, so the option renders only when both allow it.
diff --git a/ui-kit/react-native/core-features.mdx b/ui-kit/react-native/core-features.mdx
index 639a389c6..5a19c9b4a 100644
--- a/ui-kit/react-native/core-features.mdx
+++ b/ui-kit/react-native/core-features.mdx
@@ -147,6 +147,34 @@ Mentions is a feature that enhances the interactivity and clarity of group or 1-
| [MessageComposer](/ui-kit/react-native/message-composer) | [MessageComposer](/ui-kit/react-native/message-composer) component allows users to compose and send various types of messages, including support for the Mentions feature to directly address participants within the conversation. |
| [MessageList](/ui-kit/react-native/message-list) | [MessageList](/ui-kit/react-native/message-list) component displays a list of sent and received messages. It also supports rendering Mentions, enhancing the clarity and interactivity of conversations by highlighting direct references to users. |
+## Pin and Save Messages
+
+CometChat lets users **pin** important messages so they're highlighted for everyone in a conversation, and **save** messages privately to a personal list that spans every conversation. Pinned and saved messages show an indicator on the bubble, and dedicated screens let users review them.
+
+| Components | Functionality |
+| --- | --- |
+| [Message List](/ui-kit/react-native/message-list) | Adds Pin, Unpin, Save, and Unsave to the message options when the features are enabled. |
+| [Pinned Messages](/ui-kit/react-native/pinned-messages) | A screen of the messages pinned in a conversation, opened from the [Message Header](/ui-kit/react-native/message-header). |
+| [Saved Messages](/ui-kit/react-native/saved-messages) | A personal screen of the current user's saved messages across all conversations. |
+
+Your app can also cap how many items a user may pin or save through three app settings:
+
+| App setting | Caps |
+| --- | --- |
+| features.ux.messages.pinned.limit | Pinned messages per conversation |
+| features.ux.messages.saved.limit | Saved messages per user |
+| features.ux.conversations.pinned.limit | Pinned conversations per user |
+
+The UI Kit reads these settings at login. When a user reaches a cap, the kit shows a toast that names the exact limit — no extra handling required. For a full walkthrough, see the [Pin & Save Messages guide](/ui-kit/react-native/guide-pin-and-save-messages).
+
+## Pin Conversations
+
+Keep the chats that matter at the top. Users pin a conversation from the long-press menu; pinned conversations show a pin indicator and stay above the rest of the list.
+
+| Component | Role |
+| --- | --- |
+| [CometChatConversations](/ui-kit/react-native/conversations) | Provides the Pin/Unpin conversation option, the row indicator, and pinned-first ordering. |
+
## Rich Text Formatting
Rich Text Formatting allows users to style their messages with bold, italic, underline, strikethrough, code, links, lists, blockquotes, and code blocks. This brings richer expression to conversations and helps users emphasize key points.
@@ -236,6 +264,17 @@ The Threaded Conversations feature enables users to respond directly to a specif
| [MessageComposer](/ui-kit/react-native/message-composer) | [MessageComposer](/ui-kit/react-native/message-composer) component enables users to compose and send various types of messages. |
| [MessageList](/ui-kit/react-native/message-list) | [MessageList](/ui-kit/react-native/message-list) component displays a chronological list of sent and received messages. It also supports Mentions, making conversations more interactive and easier to follow by highlighting direct references to users. |
+### Thread Subscription
+
+Let users subscribe to or unsubscribe from a thread to control whether its replies notify them. Enabled by default — remove a surface with `hideThreadSubscriptionOption` or `threadSubscriptionVisibility`.
+
+| Component | Role |
+| --- | --- |
+| [CometChatMessageList](/ui-kit/react-native/message-list) | Provides the Subscribe to thread / Unsubscribe from thread option in the message action sheet. |
+| [CometChatMessageHeader](/ui-kit/react-native/message-header) | Shows the subscription bell on the thread view. |
+
+See the [Thread Subscription guide](/ui-kit/react-native/guide-threaded-messages#thread-subscription) for setup and behavior.
+
## Group Chat
CometChat facilitates Group Chats, allowing users to have conversations with multiple participants simultaneously. This feature is crucial for team collaborations, group discussions, social communities, and more.
diff --git a/ui-kit/react-native/guide-pin-and-save-messages.mdx b/ui-kit/react-native/guide-pin-and-save-messages.mdx
new file mode 100644
index 000000000..7e7b35903
--- /dev/null
+++ b/ui-kit/react-native/guide-pin-and-save-messages.mdx
@@ -0,0 +1,252 @@
+---
+title: "Pin & Save Messages"
+sidebarTitle: "Pin & Save Messages"
+description: "Let users pin important messages for everyone in a conversation and save messages privately for themselves."
+---
+
+## Goal
+
+By the end of this guide you will have a chat screen where users can **pin** a message so it's highlighted for everyone in the conversation, open a screen of all pinned messages, and **save** a message privately to their own list — with a dedicated "Saved" screen to review saves across every conversation.
+
+Pin and save are two separate concepts:
+
+| | Pin | Save |
+| --- | --- | --- |
+| **Visible to** | Everyone in the conversation | Only the current user |
+| **Scope** | One conversation | All conversations |
+| **Surfaced by** | `CometChatPinnedMessages` (per conversation) | `CometChatSavedMessages` (a personal screen) |
+| **Opened from** | The message header's pinned-messages button | Your own navigation (no built-in trigger) |
+
+## Prerequisites
+
+- Completed the [Integration Guide](/ui-kit/react-native/react-native-cli-integration)
+- An existing chat screen using `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer`
+- **Pin messages** and **Save messages** enabled for your app through the `features.ux.messages.pinned.enabled` and `features.ux.messages.saved.enabled` app settings. See [Core Features → Pin & Save](/ui-kit/react-native/core-features#pin-and-save-messages).
+
+
+The pin/unpin and save/unsave options only appear in the message options when the corresponding feature is enabled for your app. The UI Kit reads that setting at login and re-reads it on every reconnection, so no extra wiring is needed to show or hide the options.
+
+
+## Step 1: The Message Options
+
+Once the features are enabled, `CometChatMessageList` automatically adds **Pin**, **Unpin**, **Save**, and **Unsave** to the message options — no props required. You only need the `hide*` props if you want to remove one:
+
+_File: Messages.tsx_
+
+```tsx
+import { CometChatMessageList } from "@cometchat/chat-uikit-react-native";
+
+
+```
+
+The **Pin/Unpin option is shown to every member** — the UI Kit does not gate it by role. Permission is enforced by the **server**: if a member isn't allowed to pin or unpin in that conversation, the action is rejected and the UI Kit shows a permission toast. Saving is per-user and always available.
+
+
+The options are hidden on messages the server would refuse anyway — an unsent message with no ID yet, a deleted message, or one still awaiting a moderation verdict. A message sent seconds ago may briefly show no pin or save option while moderation is pending; it appears once the message is approved.
+
+
+## Step 2: Open the Pinned Messages Screen
+
+`CometChatMessageHeader` can show a pinned-messages button. Set `showPinnedMessagesButton` and wire `onPinnedMessagesPress` to navigate to `CometChatPinnedMessages`, scoped to the same `user`/`group`.
+
+_File: Messages.tsx_
+
+```tsx
+import { CometChatMessageHeader } from "@cometchat/chat-uikit-react-native";
+
+
+ navigation.navigate("PinnedMessages", { user, group })
+ }
+/>
+```
+
+_File: PinnedMessages.tsx_
+
+```tsx
+import { CometChat } from "@cometchat/chat-sdk-react-native";
+import { CometChatPinnedMessages } from "@cometchat/chat-uikit-react-native";
+import { useNavigation, useRoute } from "@react-navigation/native";
+import { SafeAreaView } from "react-native";
+
+const PinnedMessages = () => {
+ const navigation = useNavigation();
+ const route = useRoute();
+ const { user, group } = route.params ?? {};
+
+ return (
+
+ navigation.goBack()}
+ onItemPress={(message: CometChat.BaseMessage) => {
+ // Jump the main message list to this message.
+ navigation.navigate("Messages", {
+ user,
+ group,
+ messageId: String(message.getId()),
+ });
+ }}
+ />
+
+ );
+};
+
+export default PinnedMessages;
+```
+
+`CometChatPinnedMessages` is **per conversation** — it takes the same `user` or `group` the chat screen was opened with, and lists that conversation's pinned messages newest-pin first.
+
+
+
+
+
+| Prop | Type | Description |
+| --- | --- | --- |
+| `user` | `CometChat.User` | 1-1 conversation. Mutually exclusive with `group`. |
+| `group` | `CometChat.Group` | Group conversation. Mutually exclusive with `user`. |
+| `limit` | `number` | Page size. Defaults to 30; the server caps a conversation at 100. |
+| `onBack` | `() => void` | Closes the screen — rendered as the back control in the header. |
+| `onItemPress` | `(message) => void` | Tapping a row, so the host can jump its message list to that message. |
+
+## Step 3: Add a "Saved" Screen
+
+`CometChatSavedMessages` is **user-level**, not per conversation — it lists everything the logged-in user has saved, across every chat. There is no built-in entry point, so open it from your own navigation: a menu item, a profile screen, or a tab.
+
+
+
+
+
+_File: SavedMessages.tsx_
+
+```tsx
+import { CometChat } from "@cometchat/chat-sdk-react-native";
+import { CometChatSavedMessages } from "@cometchat/chat-uikit-react-native";
+import { useNavigation } from "@react-navigation/native";
+import { SafeAreaView } from "react-native";
+
+const SavedMessages = () => {
+ const navigation = useNavigation();
+
+ return (
+
+ navigation.goBack()}
+ onItemPress={async (message, source) => {
+ if (!source) return;
+ // `source` names the conversation as an id + type, so resolve it to the
+ // object the chat screen expects before navigating.
+ const party =
+ source.receiverType === "group"
+ ? { group: await CometChat.getGroup(source.receiverId) }
+ : { user: await CometChat.getUser(source.receiverId) };
+
+ navigation.navigate("Messages", {
+ ...party,
+ messageId: String(message.getId()),
+ });
+ }}
+ />
+
+ );
+};
+
+export default SavedMessages;
+```
+
+Each row shows which conversation the message came from, so a saved message is never orphaned from its context. `source` carries that conversation as `receiverType` (`"user"` or `"group"`) and `receiverId`, plus `name`, `label` and an optional `avatar` — see the [component reference](/ui-kit/react-native/saved-messages#onitempress).
+
+| Prop | Type | Description |
+| --- | --- | --- |
+| `limit` | `number` | Page size. Defaults to 30; the server caps the whole set at 100. |
+| `onBack` | `() => void` | Closes the screen. |
+| `onItemPress` | `(message, source) => void` | Receives the message and its resolved source conversation. |
+
+## Step 4: Pinned & Saved Indicators
+
+No wiring needed. `CometChatMessageList` renders a pin glyph and a filled bookmark in the message's meta row, beside the timestamp, and keeps them in sync in real time:
+
+- **Pin** is conversation-wide, so every participant sees the indicator appear and disappear as the message is pinned or unpinned.
+- **Save** is private, so the indicator appears only for the user who saved it — and syncs to that user's **other devices**.
+
+## Step 5: Limits
+
+Both features are capped by the server, per app:
+
+| Limit | Applies to |
+| --- | --- |
+| Pinned messages | Per conversation |
+| Saved messages | Per user, across all conversations |
+
+When a cap is reached, the action is rejected and the UI Kit shows a toast carrying the **server-provided limit** — the number is never hard-coded in the kit, so raising the cap for your app changes the message automatically.
+
+## Complete Example
+
+_File: Messages.tsx_
+
+```tsx
+import { CometChat } from "@cometchat/chat-sdk-react-native";
+import {
+ CometChatMessageComposer,
+ CometChatMessageHeader,
+ CometChatMessageList,
+} from "@cometchat/chat-uikit-react-native";
+import { useNavigation, useRoute } from "@react-navigation/native";
+import { View } from "react-native";
+
+const Messages = ({ user, group }: { user?: CometChat.User; group?: CometChat.Group }) => {
+ const navigation = useNavigation();
+ const route = useRoute();
+ // Set when this screen was opened from the Pinned or Saved list.
+ const goToMessageId = route.params?.messageId;
+
+ return (
+
+
+ navigation.navigate("PinnedMessages", { user, group })
+ }
+ />
+
+
+
+
+
+
+
+ );
+};
+
+export default Messages;
+```
+
+`goToMessageId` is what makes the jump actually happen: `CometChatMessageList` fetches the page around that ID and scrolls to it, so tapping a pinned or saved row lands on the message in its original conversation.
+
+## Next Steps
+
+- [CometChatPinnedMessages](/ui-kit/react-native/pinned-messages) — the full component reference
+- [CometChatSavedMessages](/ui-kit/react-native/saved-messages) — the full component reference
+- [Pin Message (SDK)](/sdk/react-native/pin-message) — the underlying SDK methods and listeners
+- [Save Message (SDK)](/sdk/react-native/save-message)
+- [Pin Conversation](/ui-kit/react-native/core-features#pin-conversations) — pinning a whole chat to the top of the list
diff --git a/ui-kit/react-native/guide-threaded-messages.mdx b/ui-kit/react-native/guide-threaded-messages.mdx
index 044e4f613..8442306f9 100644
--- a/ui-kit/react-native/guide-threaded-messages.mdx
+++ b/ui-kit/react-native/guide-threaded-messages.mdx
@@ -126,7 +126,7 @@ export default ThreadView;
### 2. Trigger Thread View from Messages
-In your main messages screen, handle the `onThreadRepliesClick` callback to navigate to the thread view.
+In your main messages screen, handle the `onThreadRepliesPress` callback to navigate to the thread view.
```tsx
import React from 'react';
@@ -147,7 +147,7 @@ interface MessagesScreenProps {
const MessagesScreen: React.FC = ({ user, group }) => {
const navigation = useNavigation();
- const handleThreadRepliesClick = (message: CometChat.BaseMessage) => {
+ const handleThreadRepliesPress = (message: CometChat.BaseMessage) => {
navigation.navigate('ThreadView', {
message,
user,
@@ -162,7 +162,7 @@ const MessagesScreen: React.FC = ({ user, group }) => {
@@ -280,6 +280,77 @@ const ThreadComposer: React.FC = ({ user, group, parentMess
---
+## Thread Subscription
+
+Users can *subscribe* to a thread to keep getting updates about new replies even when they aren't actively viewing it, and *unsubscribe* to stop. This works in both 1-1 and group conversations. The UI Kit surfaces it in two places, both wired out of the box:
+
+- A **bell** in `CometChatMessageHeader`, shown once the header is given a `parentMessage`.
+- A **subscribe / unsubscribe option** in the message options of `CometChatMessageList`.
+
+Both reflect the current subscription state, flip it optimistically on tap, and show a message if the server rejects the change. No wiring is required to make them work.
+
+
+On React Native the bell is on [CometChatMessageHeader](/ui-kit/react-native/message-header#thread-subscription), not `CometChatThreadHeader`. The landed design places it in the thread screen's top bar rather than in the reply-count row, so `parentMessage` is what puts the header in thread mode and renders it.
+
+
+```tsx
+import {
+ CometChatMessageHeader,
+ CometChatMessageList,
+ CometChatThreadHeader,
+} from "@cometchat/chat-uikit-react-native";
+
+// Top bar — `parentMessage` renders the bell
+
+
+// Reply-count row
+
+
+// Pass the whole parent message, not just its id — a reply arriving over the socket
+// carries no subscription flag, so the list stamps it from the thread's parent.
+
+```
+
+### Automatic subscription
+
+Beyond the manual bell and message option, the UI Kit subscribes a user to a thread automatically in a few cases, so people keep getting updates on threads they are actually part of — without having to remember to follow them:
+
+- **Sending a message subscribes you to its thread.** Sending a reply inside a thread subscribes you to that thread as well.
+- **Being @mentioned in a reply subscribes you**, whether the mention is added on a fresh reply or introduced by an edit.
+- **A reply from someone else that does not mention you does not subscribe you.** You are only pulled in when you author something in the thread or you are mentioned.
+
+These rules apply in real time and across devices, and a change is mirrored to both surfaces whether or not the thread screen is open.
+
+A deliberate **unsubscribe is remembered** and survives a reload, but sending another message in that thread, or being mentioned in it again, re-subscribes you.
+
+### Reacting to changes
+
+Pass `onThreadSubscriptionChange` to the message header to run your own logic when the user subscribes or unsubscribes:
+
+```tsx
+
+ console.log(subscribed ? "Subscribed to thread" : "Unsubscribed from thread")
+ }
+/>
+```
+
+### Hiding the controls
+
+Each surface is hidden independently — an integrator may want one and not the other.
+
+- `threadSubscriptionVisibility` on [`CometChatMessageHeader`](/ui-kit/react-native/message-header#thread-subscription) removes the bell.
+- `hideThreadSubscriptionOption` on [`CometChatMessageList`](/ui-kit/react-native/message-list) removes the message option.
+
## Feature Matrix
| Feature | Component / Prop |
@@ -288,7 +359,7 @@ const ThreadComposer: React.FC = ({ user, group, parentMess
| Show thread replies | `CometChatMessageList` with `parentMessageId` prop |
| Compose thread reply | `CometChatMessageComposer` with `parentMessageId` prop |
| Navigate to message | `goToMessageId` prop on `CometChatMessageList` |
-| Thread trigger | `onThreadRepliesClick` callback on `CometChatMessageList` |
+| Thread trigger | `onThreadRepliesPress` callback on `CometChatMessageList` |
---
diff --git a/ui-kit/react-native/message-header.mdx b/ui-kit/react-native/message-header.mdx
index 036f166f7..2a6d84aec 100644
--- a/ui-kit/react-native/message-header.mdx
+++ b/ui-kit/react-native/message-header.mdx
@@ -436,6 +436,101 @@ function TrailingViewDemo() {
---
+## Pinned Messages
+
+`CometChatMessageHeader` can show a button that opens a conversation's pinned messages. It is **off by default** — set `showPinnedMessagesButton` to render it, and `onPinnedMessagesPress` to handle the tap.
+
+```tsx lines
+showPinnedMessagesButton?: boolean // default: false
+onPinnedMessagesPress?: () => void
+```
+
+The component does not navigate for you: it raises the tap and you decide where to go, so the button works with any navigation setup.
+
+```tsx lines
+import { CometChatMessageHeader } from "@cometchat/chat-uikit-react-native";
+import { useNavigation } from "@react-navigation/native";
+
+function ChatHeader({ user, group }) {
+ const navigation = useNavigation();
+
+ return (
+
+ navigation.navigate("PinnedMessages", { user, group })
+ }
+ />
+ );
+}
+```
+
+Render [CometChatPinnedMessages](/ui-kit/react-native/pinned-messages) on that screen, scoped to the same `user`/`group`. See the [Pin & Save Messages guide](/ui-kit/react-native/guide-pin-and-save-messages) for the full flow.
+
+
+Pin must be enabled for your app in the CometChat Dashboard. The UI Kit reads that setting at login, so the button opens a panel that stays empty if the feature is off for your app.
+
+
+## Thread Subscription
+
+When the header is given a `parentMessage`, it switches to **thread mode** and renders a bell that subscribes the user to that thread or unsubscribes them. Without `parentMessage` there is no thread to follow, so no bell renders — a conversation header can never accidentally show a thread control.
+
+```tsx lines
+parentMessage?: CometChat.BaseMessage // set this to enter thread mode
+threadSubscriptionVisibility?: boolean // default: true
+onThreadSubscriptionChange?: (subscribed: boolean) => void
+```
+
+```tsx lines
+import { CometChat } from "@cometchat/chat-sdk-react-native";
+import { CometChatMessageHeader } from "@cometchat/chat-uikit-react-native";
+import { Text } from "react-native";
+
+function ThreadHeader({
+ parentMessage,
+ user,
+ group,
+ onBack,
+}: {
+ parentMessage: CometChat.BaseMessage;
+ user?: CometChat.User;
+ group?: CometChat.Group;
+ onBack: () => void;
+}) {
+ return (
+
+ console.log(subscribed ? "Following this thread" : "No longer following")
+ }
+ // A thread bar names the screen, not the person, and calls belong to a
+ // conversation rather than a thread.
+ hideVoiceCallButton={true}
+ hideVideoCallButton={true}
+ LeadingView={() => <>>}
+ TitleView={() => Thread}
+ />
+ );
+}
+```
+
+The bell manages itself: it reads the current state, flips optimistically on tap, reverts if the server rejects the change, and stays in step with a toggle made from the message action sheet.
+
+To hide it on a particular screen, pass `threadSubscriptionVisibility={false}`:
+
+```tsx lines
+
+```
+
+The same subscribe/unsubscribe action is also offered as a message option on [CometChatMessageList](/ui-kit/react-native/message-list), hidden independently with `hideThreadSubscriptionOption` — an integrator may want one surface and not the other. See the [Thread Subscription guide](/ui-kit/react-native/guide-threaded-messages#thread-subscription).
+
## Styling
Using Style you can customize the look and feel of the component in your app. Pass a styling object as a prop to the `CometChatMessageHeader` component.
@@ -488,6 +583,8 @@ function StylingDemo() {
| `usersStatusVisibility` | Toggle user status visibility | `usersStatusVisibility?: boolean` |
| `hideNewChatButton` | Toggle visibility of new chat button for AI Assistants | `hideNewChatButton?: boolean` |
| `hideChatHistoryButton` | Toggle visibility of chat history button for AI Assistants | `hideChatHistoryButton?: boolean` |
+| `showPinnedMessagesButton` | Toggle visibility of the pinned-messages button. Off by default | `showPinnedMessagesButton?: boolean` |
+| `threadSubscriptionVisibility` | Toggle visibility of the thread subscription bell. Requires `parentMessage` | `threadSubscriptionVisibility?: boolean` |
### options
diff --git a/ui-kit/react-native/message-list.mdx b/ui-kit/react-native/message-list.mdx
index 57db017ba..d5f524522 100644
--- a/ui-kit/react-native/message-list.mdx
+++ b/ui-kit/react-native/message-list.mdx
@@ -448,33 +448,10 @@ These actions appear in the message options sheet, each with a prop to hide it.
every reconnect, so an option renders only when the Dashboard allows it *and* the prop does not
hide it. There is no start-up call to make.
- Thread subscription is different: it is not an app setting, so `ThreadSubscriptionConfig` is a real
- switch — and it defaults to **on**, matching the React UI Kit. The option shows unless you opt out.
+ Thread subscription is different: it is not an app setting. The option shows by default, matching
+ the React UI Kit, so `hideThreadSubscriptionOption` is how you remove it.
-
-
-```typescript
-import { ThreadSubscriptionConfig } from "@cometchat/chat-uikit-react-native";
-
-// Thread subscription is on by default — call this only to opt OUT.
-// Pin and Save need no equivalent: the kit reads their Dashboard flags at login.
-ThreadSubscriptionConfig.setEnabled(false);
-```
-
-
-
-
-```javascript
-import { ThreadSubscriptionConfig } from "@cometchat/chat-uikit-react-native";
-
-ThreadSubscriptionConfig.setEnabled(false);
-```
-
-
-
-
-
The Dashboard flag and the per-instance prop are **ANDed**: the Dashboard decides whether a feature is
available to your app at all, and these props hide it on one particular list.
@@ -1197,7 +1174,7 @@ Hides suggested messages in AI view.
### hideThreadSubscriptionOption
-Hides the "Follow / Unfollow thread" option. Unlike pin and save, `ThreadSubscriptionConfig` defaults to **on**, so this prop is the usual way to hide it.
+Hides the "Follow / Unfollow thread" option. Unlike pin and save, it is not gated on a Dashboard setting — the option shows by default, so this prop is how you hide it.
| | |
| --- | --- |
diff --git a/ui-kit/react-native/pinned-messages.mdx b/ui-kit/react-native/pinned-messages.mdx
index 62e46eafb..2ee413540 100644
--- a/ui-kit/react-native/pinned-messages.mdx
+++ b/ui-kit/react-native/pinned-messages.mdx
@@ -14,7 +14,7 @@ description: "Display the messages pinned in a conversation, with unpin, save, c
"description": "Lists the messages pinned in a conversation, newest pin first. A pin is conversation-wide and visible to everyone.",
"requires": {
"dashboardFlag": "Pin Messages must be enabled for your app in the CometChat Dashboard",
- "resolution": "The kit reads the flag at login and on every reconnect — no app code required. Force a re-read with refreshPinSaveFeatures()"
+ "resolution": "The kit reads the flag at login and re-reads it on every reconnection — no app code required"
},
"props": {
"data": {
@@ -39,10 +39,6 @@ description: "Display the messages pinned in a conversation, with unpin, save, c
"title": { "type": "string", "default": "localized" },
"style": "DeepPartial"
}
- },
- "helpers": {
- "isPinned": "(message) => boolean",
- "isSystemPin": "(message) => boolean — pinnedBy is SYSTEM_PINNER (\"app_system\")"
}
}
```
@@ -62,6 +58,13 @@ conversation-wide and visible to everyone, so this panel shows the same set to e
Open it from the message header or an overflow menu, scoped to the conversation the user is in. It is
a full-screen panel with its own back affordance rather than an inline strip.
+
+
+
+
## Minimal Render
Pass **exactly one** of `user` or `group` — the panel is scoped to a single conversation.
@@ -95,168 +98,146 @@ import { CometChatPinnedMessages } from "@cometchat/chat-uikit-react-native";
-## Enabling the feature
+## Actions and Events
-Pin and Save are gated on your app's Dashboard settings. The UI Kit resolves those flags at login
-and on every reconnect and switches the options on or off accordingly, so there is nothing to call
-at start-up.
+### Callback Props
-`PinSaveConfig` is exported for the cases where you need to read or override that resolved state —
-not as a switch you must throw.
+#### onItemPress
-
-
-```typescript
-import {
- PinSaveConfig,
- refreshPinSaveFeatures,
- getPinSaveFeatures,
-} from "@cometchat/chat-uikit-react-native";
+Fires when a pinned row is tapped. The panel does not navigate for you — use it to close the panel and jump your message list to that message.
-// Read what the kit resolved from the Dashboard flags
-const features = getPinSaveFeatures();
+```tsx lines
+import { CometChatPinnedMessages } from "@cometchat/chat-uikit-react-native";
+import { CometChat } from "@cometchat/chat-sdk-react-native";
+
+function PinnedWithJump({ group }: { group: CometChat.Group }) {
+ const handleItemPress = (message: CometChat.BaseMessage) => {
+ navigation.goBack();
+ scrollToMessageId(message.getId());
+ };
-// Force a re-read after flipping a flag in the dashboard, without a re-login
-await refreshPinSaveFeatures();
+ return ;
+}
```
-
+#### onBack
-
-```javascript
-import {
- PinSaveConfig,
- refreshPinSaveFeatures,
- getPinSaveFeatures,
-} from "@cometchat/chat-uikit-react-native";
+Fires when the back affordance in the header is pressed.
-const features = getPinSaveFeatures();
-refreshPinSaveFeatures();
+```tsx lines
+ navigation.goBack()} />
```
-
+### Events
-
+The panel keeps itself current from the kit's event bus, so a pin made anywhere — this screen, the message list, or another participant's device — lands here without a manual refresh.
+
+| Event | Fires when |
+| --- | --- |
+| `ccMessagePinned` / `ccMessageUnpinned` | This device pinned or unpinned. |
+| `ccMessageSaved` / `ccMessageUnsaved` | This device saved or unsaved. |
+| `onMessagePinned` / `onMessageUnpinned` | Another participant pinned or unpinned — broadcast to everyone. |
+| `onMessageSaved` / `onMessageUnsaved` | The same user saved on another device — private multi-device. |
- You do not need to fetch these flags yourself, and you do not need to enable the feature in code.
- The kit resolves them at login and after every reconnect. `refreshPinSaveFeatures()` exists for the
- case where an admin flips a flag in the Dashboard while the app is running.
+ **Removing asks, adding does not.** Unpin and Unsave show a confirmation; Pin and Save run
+ immediately. This is deliberate and consistent across all CometChat UI Kits — the additive action
+ has its own undo one tap away, the destructive one does not.
-## Props
-
-| Property | Type | Default | Description |
-| --- | --- | --- | --- |
-| `user` | `CometChat.User` | — | Scopes the panel to a one-on-one conversation. Mutually exclusive with `group`. |
-| `group` | `CometChat.Group` | — | Scopes the panel to a group. Mutually exclusive with `user`. |
-| `limit` | `number` | `30` | Page size for the fetch. The SDK rejects a value above 100. |
-| `onBack` | `() => void` | — | Called when the back affordance is pressed. |
-| `onItemPress` | `(message) => void` | — | Called when a row is pressed — use it to jump to the message in the list. |
-| `hideUnpinMessageOption` | `boolean` | `false` | Hides Unpin in the row menu. |
-| `hideSaveMessageOption` | `boolean` | `false` | Hides Save in the row menu. |
-| `hideUnsaveMessageOption` | `boolean` | `false` | Hides Unsave in the row menu. |
-| `hideCopyMessageOption` | `boolean` | `false` | Hides Copy. |
-| `hideShareMessageOption` | `boolean` | `false` | Hides Share. |
-| `hideMessageInfoOption` | `boolean` | `false` | Hides Message Info. |
-| `ItemView` | `(message) => JSX.Element` | — | Replaces the default row entirely. |
-| `title` | `string` | localized | Panel title. |
-| `style` | `DeepPartial` | — | Style overrides. |
-
-## Reading pin state yourself
-
-The kit exports helpers so a custom `ItemView` does not have to reimplement them. The SDK has no
-`isPinned()` of its own — these are UI Kit conveniences over `getPinnedAt()` and `getPinnedBy()`.
-
-
-
-```typescript
-import { isPinned, isSystemPin, SYSTEM_PINNER } from "@cometchat/chat-uikit-react-native";
-
-if (isPinned(message)) {
- // Pinned by somebody in this conversation
-}
+---
-if (isSystemPin(message)) {
- // An admin/global pin — pinnedBy is SYSTEM_PINNER ("app_system"), not a real member
-}
-```
+## Opening from the Message Header
-
+`CometChatMessageHeader` can raise the entry point for you. Set `showPinnedMessagesButton` and handle `onPinnedMessagesPress`.
-
-```javascript
-import { isPinned, isSystemPin } from "@cometchat/chat-uikit-react-native";
+
+ Despite the name, this is **not a standalone button**. It adds a localized **"Pinned Messages" item
+ to the header's `⋮` overflow menu**, alongside anything your own `options` prop contributes. On a
+ header with no other menu items, turning it on is what makes the `⋮` appear at all.
+
-if (isPinned(message)) {
- // Pinned by somebody in this conversation
-}
+```tsx lines
+import {
+ CometChatMessageHeader,
+ CometChatMessageList,
+} from "@cometchat/chat-uikit-react-native";
-if (isSystemPin(message)) {
- // An admin/global pin
+function Messages({ user, group }) {
+ return (
+ <>
+
+ navigation.navigate("PinnedMessages", { user, group })
+ }
+ />
+
+ >
+ );
}
```
-
+
+ **Both props are required.** `showPinnedMessagesButton={true}` on its own does nothing — the menu
+ item is only added when `onPinnedMessagesPress` is also supplied, and there is no warning when it
+ is missing.
+
-
+---
-## Actions and Events
+## Custom View Slots
-The panel keeps itself current from the kit's event bus, so a pin made anywhere — this screen, the
-message list, or another participant's device — lands here without a manual refresh.
+| Slot | Signature | Replaces |
+| --- | --- | --- |
+| `ItemView` | `(message: CometChat.BaseMessage) => JSX.Element` | Entire pinned row — sender line and bubble |
-| Event | Fires when |
-| --- | --- |
-| `ccMessagePinned` / `ccMessageUnpinned` | This device pinned or unpinned. |
-| `ccMessageSaved` / `ccMessageUnsaved` | This device saved or unsaved. |
-| `onMessagePinned` / `onMessageUnpinned` | Another participant pinned or unpinned — broadcast to everyone. |
-| `onMessageSaved` / `onMessageUnsaved` | The same user saved on another device — private multi-device. |
+The empty, error and loading states are not view slots on this component. Restyle them through `style.emptyStateStyle` and `style.errorStateStyle` instead — see [Styling](#styling).
-
- **Removing asks, adding does not.** Unpin and Unsave show a confirmation; Pin and Save run
- immediately. This is deliberate and consistent across all CometChat UI Kits — the additive action
- has its own undo one tap away, the destructive one does not.
-
+### ItemView
-## Common Patterns
+Replace the whole row, including the sender line above the bubble.
-### Jump to the pinned message
+```tsx lines
+import { CometChatPinnedMessages, useTheme } from "@cometchat/chat-uikit-react-native";
+import { CometChat } from "@cometchat/chat-sdk-react-native";
+import { View, Text } from "react-native";
-
-
-```tsx
- {
- navigation.goBack();
- scrollToMessageId(message.getId());
- }}
-/>
-```
+function CustomPinnedRow({ group }: { group: CometChat.Group }) {
+ const theme = useTheme();
-
+ const getItemView = (message: CometChat.BaseMessage) => (
+
+
+ {message.getSender()?.getName()}
+
+
+ {(message as CometChat.TextMessage).getText?.()}
+
+
+ );
-
-```jsx
- {
- navigation.goBack();
- scrollToMessageId(message.getId());
- }}
-/>
+ return ;
+}
```
-
+---
-
+## Common Patterns
### Read-only panel
-
-
-```tsx
+Hide every mutating action and leave the panel as a reference list.
+
+```tsx lines
```
-
+### A custom title and close icon
-
-```jsx
+```tsx lines
```
-
+---
-
+## Styling
+
+The component uses the theme system from `CometChatThemeProvider`. Pass a `style` prop to customize the appearance. Every default value resolves from a semantic theme token, so retheming the kit restyles this panel without touching it.
+
+```tsx lines
+import { CometChatPinnedMessages } from "@cometchat/chat-uikit-react-native";
+
+function StyledPinnedMessages({ group }) {
+ return (
+
+ );
+}
+```
+
+### Style Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| `containerStyle` | `ViewStyle` | Root container |
+| `headerContainerStyle` | `ViewStyle` | Header row holding the back control and title |
+| `titleStyle` | `TextStyle` | Header title text |
+| `closeButtonIconStyle` | `ImageStyle` | Size and tint of the back control |
+| `closeButtonIcon` | `ImageSourcePropType \| JSX.Element` | Replaces the back icon itself |
+| `itemStyle` | `object` | One pinned row — see below |
+| `emptyStateStyle` | `object` | `containerStyle`, `titleStyle`, `subTitleStyle`, `iconStyle` |
+| `errorStateStyle` | `object` | `containerStyle`, `titleStyle`, `subTitleStyle`, `iconStyle` |
+
+`itemStyle` keys:
+
+| Property | Type | Description |
+| --- | --- | --- |
+| `containerStyle` | `ViewStyle` | The row |
+| `headerContainerStyle` | `ViewStyle` | Avatar + sender name + date line above the bubble |
+| `avatarStyle` | `object` | Sender avatar |
+| `senderNameStyle` | `TextStyle` | Sender name |
+| `separatorStyle` | `TextStyle` | Divider between sender name and date |
+| `dateStyle` | `object` | Pin timestamp |
+| `savedIndicatorStyle` | `ImageStyle` | Bookmark shown when a pinned message is **also** saved by this viewer |
+| `savedIndicatorContainerStyle` | `ViewStyle` | Wrapper around that bookmark |
+| `bubbleContainerStyle` | `ViewStyle` | Left inset that lines the bubble up under the sender name |
+
+---
+
+## Props
+
+Provide either `user` or `group`, not both. All other props are optional.
+
+### user
+
+Scopes the panel to a one-on-one conversation.
+
+| | |
+| --- | --- |
+| Type | `CometChat.User` |
+| Default | — |
+
+Mutually exclusive with `group`.
+
+---
+
+### group
+
+Scopes the panel to a group conversation.
+
+| | |
+| --- | --- |
+| Type | `CometChat.Group` |
+| Default | — |
+
+Mutually exclusive with `user`.
+
+---
+
+### limit
+
+Page size for the fetch.
+
+| | |
+| --- | --- |
+| Type | `number` |
+| Default | `30` |
+
+The server rejects a value above 100.
+
+---
+
+### onBack
+
+Called when the back affordance is pressed.
+
+| | |
+| --- | --- |
+| Type | `() => void` |
+| Default | — |
+
+---
+
+### onItemPress
+
+Called when a row is pressed.
+
+| | |
+| --- | --- |
+| Type | `(message: CometChat.BaseMessage) => void` |
+| Default | — |
+
+---
+
+### hideUnpinMessageOption
+
+Hides **Unpin** in the row's long-press menu.
+
+| | |
+| --- | --- |
+| Type | `boolean` |
+| Default | `false` |
+
+---
+
+### hideSaveMessageOption
+
+Hides **Save** in the row's long-press menu.
+
+| | |
+| --- | --- |
+| Type | `boolean` |
+| Default | `false` |
+
+---
+
+### hideUnsaveMessageOption
+
+Hides **Unsave** in the row's long-press menu.
+
+| | |
+| --- | --- |
+| Type | `boolean` |
+| Default | `false` |
+
+---
+
+### hideCopyMessageOption
+
+Hides **Copy**.
+
+| | |
+| --- | --- |
+| Type | `boolean` |
+| Default | `false` |
+
+---
+
+### hideShareMessageOption
+
+Hides **Share**.
+
+| | |
+| --- | --- |
+| Type | `boolean` |
+| Default | `false` |
+
+---
+
+### hideMessageInfoOption
+
+Hides **Message Info**.
+
+| | |
+| --- | --- |
+| Type | `boolean` |
+| Default | `false` |
+
+---
+
+### ItemView
+
+Replaces the default row entirely.
+
+| | |
+| --- | --- |
+| Type | `(message: CometChat.BaseMessage) => JSX.Element` |
+| Default | — |
+
+---
+
+### title
+
+Panel title.
+
+| | |
+| --- | --- |
+| Type | `string` |
+| Default | Localized "Pinned Messages" |
+
+---
+
+### style
+
+Per-instance style overrides, merged over the theme's `pinnedMessagesStyles`.
+
+| | |
+| --- | --- |
+| Type | `DeepPartial` |
+| Default | — |
+
+See [Styling](#styling).
---
diff --git a/ui-kit/react-native/saved-messages.mdx b/ui-kit/react-native/saved-messages.mdx
index 9a6199556..4ef35941e 100644
--- a/ui-kit/react-native/saved-messages.mdx
+++ b/ui-kit/react-native/saved-messages.mdx
@@ -14,7 +14,7 @@ description: "Display the logged-in user's saved messages across every conversat
"description": "Lists every message the logged-in user has saved, newest save first. A save is private and spans all conversations, so there is no user or group prop.",
"requires": {
"dashboardFlag": "Save Messages must be enabled for your app in the CometChat Dashboard",
- "resolution": "The kit reads the flag at login and on every reconnect — no app code required. Force a re-read with refreshPinSaveFeatures()"
+ "resolution": "The kit reads the flag at login and re-reads it on every reconnection — no app code required"
},
"props": {
"data": {
@@ -32,9 +32,6 @@ description: "Display the logged-in user's saved messages across every conversat
"title": { "type": "string", "default": "localized" },
"style": "DeepPartial"
}
- },
- "helpers": {
- "isSaved": "(message) => boolean — savedAt is per-viewer, always about the logged-in user"
}
}
```
@@ -55,6 +52,13 @@ to a single chat.
Because the list is account-wide, this panel belongs at app level — a tab, a drawer entry, or a
profile screen — not inside a single conversation.
+
+
+
+
## Minimal Render
There is deliberately no `user` or `group` prop. Scoping it to one conversation would defeat the point.
@@ -91,45 +95,48 @@ import { CometChatSavedMessages } from "@cometchat/chat-uikit-react-native";
-## Props
+## Actions and Events
-| Property | Type | Default | Description |
-| --- | --- | --- | --- |
-| `limit` | `number` | `30` | Page size for the fetch. The SDK rejects a value above 100. |
-| `onBack` | `() => void` | — | Called when the back affordance is pressed. |
-| `onItemPress` | `(message, source) => void` | — | Called when a row is pressed. `source` identifies which conversation the message belongs to. |
-| `hideUnsaveMessageOption` | `boolean` | `false` | Hides Unsave in the row menu. |
-| `ItemView` | `(message) => JSX.Element` | — | Replaces the default row entirely. |
-| `title` | `string` | localized | Panel title. |
-| `style` | `DeepPartial` | — | Style overrides. |
+### Callback Props
-## Routing a tap back to its conversation
+#### onItemPress
-Because the rows come from different conversations, `onItemPress` hands you a `source` alongside the
-message. If you build a custom `ItemView`, the message itself carries the same context.
+Fires when a saved row is tapped. Because the rows come from different conversations, it hands you a `source` alongside the message so you can open the right chat.
-
-
-```tsx
- {
- const conversationId = message.getConversationId();
- const receiverType = message.getReceiverType(); // "user" or "group"
- const receiverId = message.getReceiverId();
+```tsx lines
+import { CometChatSavedMessages } from "@cometchat/chat-uikit-react-native";
+import { CometChat } from "@cometchat/chat-sdk-react-native";
+
+function SavedWithRouting() {
+ const handleItemPress = (message: CometChat.BaseMessage, source) => {
+ navigation.navigate("Messages", {
+ receiverType: source?.receiverType, // "user" | "group"
+ receiverId: source?.receiverId,
+ messageId: String(message.getId()),
+ });
+ };
- navigateToConversation({ receiverType, receiverId, conversationId });
- }}
-/>
+ return ;
+}
```
-
+`source` is `null` when the conversation could not be resolved. Otherwise it carries:
-
-```jsx
+| Field | Type | Description |
+| --- | --- | --- |
+| `receiverType` | `string` | `"user"` or `"group"` — drives the open-conversation call |
+| `receiverId` | `string` | The GUID, or the UID of the other party in a 1-1 |
+| `name` | `string` | Plain display name — what the row title shows |
+| `label` | `string` | Display text with its sigil, e.g. `#engineering` or `@alice` |
+| `avatar` | `string?` | Group icon or user avatar, when the payload carries a hydrated party |
+
+You can also read the routing off the message itself:
+
+```tsx lines
{
+ onItemPress={(message: CometChat.BaseMessage) => {
navigateToConversation({
- receiverType: message.getReceiverType(),
+ receiverType: message.getReceiverType(), // "user" or "group"
receiverId: message.getReceiverId(),
conversationId: message.getConversationId(),
});
@@ -137,63 +144,79 @@ message. If you build a custom `ItemView`, the message itself carries the same c
/>
```
-
+#### onBack
-
+Fires when the back affordance in the header is pressed.
-## Reading save state yourself
+```tsx lines
+ navigation.goBack()} />
+```
-
-
-```typescript
-import { isSaved } from "@cometchat/chat-uikit-react-native";
+### Events
-if (isSaved(message)) {
- // The logged-in user saved this one
-}
-```
+| Event | Fires when |
+| --- | --- |
+| `ccMessageSaved` / `ccMessageUnsaved` | This device saved or unsaved. |
+| `onMessageSaved` / `onMessageUnsaved` | The same user saved on **another** device. |
-
+
+ The panel keeps itself current without a manual refresh, so a save made on a phone appears on that
+ user's tablet on its own.
+
-
-```javascript
-import { isSaved } from "@cometchat/chat-uikit-react-native";
+
+ A save is **per-viewer**. The same message reads saved for the user who saved it and unsaved for
+ everybody else — it is never a property of the message globally.
+
-if (isSaved(message)) {
- // The logged-in user saved this one
-}
-```
+---
-
+## Custom View Slots
-
+| Slot | Signature | Replaces |
+| --- | --- | --- |
+| `ItemView` | `(message: CometChat.BaseMessage) => JSX.Element` | Entire saved row |
-
- `savedAt` is **per-viewer**. The same message reads saved for the user who saved it and unsaved for
- everybody else — so `isSaved()` is always a statement about the logged-in user, never about the
- message globally.
-
+The empty, error and loading states are not view slots on this component. Restyle them through `style.emptyStateStyle` and `style.errorStateStyle` instead — see [Styling](#styling).
-## Actions and Events
+### ItemView
-| Event | Fires when |
-| --- | --- |
-| `ccMessageSaved` / `ccMessageUnsaved` | This device saved or unsaved. |
-| `onMessageSaved` / `onMessageUnsaved` | The same user saved on **another** device. |
+Replace the whole row. The default row is a conversation row — avatar, source conversation name, and a one-line preview — so a replacement usually wants the same three pieces.
-
- The SDK listener never fires on the device that performed the save — that device already has the
- resolved message. The panel updates from the local event there, and from the SDK event everywhere
- else, so a save on a phone appears on a tablet without a refresh.
-
+```tsx lines
+import { CometChatSavedMessages, useTheme } from "@cometchat/chat-uikit-react-native";
+import { CometChat } from "@cometchat/chat-sdk-react-native";
+import { View, Text } from "react-native";
+
+function CustomSavedRow() {
+ const theme = useTheme();
+
+ const getItemView = (message: CometChat.BaseMessage) => (
+
+
+ {message.getReceiverId()}
+
+
+ {(message as CometChat.TextMessage).getText?.()}
+
+
+ );
+
+ return ;
+}
+```
+
+---
## Common Patterns
### A saved-messages tab
-
-
-```tsx
+Because the list is account-wide, a tab or drawer entry is the natural home for it.
+
+```tsx lines
(
@@ -204,40 +227,156 @@ if (isSaved(message)) {
/>
```
-
+### Read-only list
-
-```jsx
- (
- openConversation(message)} />
- )}
+```tsx lines
+
+```
+
+### A custom title and close icon
+
+```tsx lines
+
```
-
+---
-
+## Styling
-### Read-only list
+The component uses the theme system from `CometChatThemeProvider`. Pass a `style` prop to customize the appearance. Every default value resolves from a semantic theme token, so retheming the kit restyles this panel without touching it.
-
-
-```tsx
-
+```tsx lines
+import { CometChatSavedMessages } from "@cometchat/chat-uikit-react-native";
+
+function StyledSavedMessages() {
+ return (
+
+ );
+}
```
-
+
+ `SavedMessagesStyle` deliberately has **no `itemStyle`**. The rows are conversation rows and take
+ their chrome from `theme.conversationStyles.itemStyle` — the same tokens the conversation list
+ uses — so the two surfaces cannot drift apart. Restyle the rows there and both update together.
+
-
-```jsx
-
-```
+### Style Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| `containerStyle` | `ViewStyle` | Root container |
+| `headerContainerStyle` | `ViewStyle` | Header row holding the back control and title |
+| `titleStyle` | `TextStyle` | Header title text |
+| `closeButtonIconStyle` | `ImageStyle` | Size and tint of the back control |
+| `closeButtonIcon` | `ImageSourcePropType \| JSX.Element` | Replaces the back icon itself |
+| `previewIconStyle` | `ImageStyle` | Type glyph in the row subtitle — image, video, audio, file, sticker |
+| `previewIconContainerStyle` | `ViewStyle` | Wrapper around that glyph |
+| `menuIconStyle` | `ImageStyle` | Glyph in the long-press menu (Unsave) |
+| `emptyStateStyle` | `object` | `containerStyle`, `titleStyle`, `subTitleStyle`, `iconStyle` |
+| `errorStateStyle` | `object` | `containerStyle`, `titleStyle`, `subTitleStyle`, `iconStyle` |
-
+---
-
+## Props
+
+All props are optional. There is deliberately no `user` or `group` prop — see [Minimal Render](#minimal-render).
+
+### limit
+
+Page size for the fetch.
+
+| | |
+| --- | --- |
+| Type | `number` |
+| Default | `30` |
+
+The server rejects a value above 100.
+
+---
+
+### onBack
+
+Called when the back affordance is pressed.
+
+| | |
+| --- | --- |
+| Type | `() => void` |
+| Default | — |
+
+---
+
+### onItemPress
+
+Called when a row is pressed. `source` identifies which conversation the message belongs to.
+
+| | |
+| --- | --- |
+| Type | `(message: CometChat.BaseMessage, source: SavedMessageSource \| null) => void` |
+| Default | — |
+
+The `source` fields are listed under [Callback Props](#onitempress).
+
+---
+
+### hideUnsaveMessageOption
+
+Hides **Unsave** in the row's long-press menu.
+
+| | |
+| --- | --- |
+| Type | `boolean` |
+| Default | `false` |
+
+---
+
+### ItemView
+
+Replaces the default row entirely.
+
+| | |
+| --- | --- |
+| Type | `(message: CometChat.BaseMessage) => JSX.Element` |
+| Default | — |
+
+---
+
+### title
+
+Panel title.
+
+| | |
+| --- | --- |
+| Type | `string` |
+| Default | Localized "Saved Messages" |
+
+---
+
+### style
+
+Per-instance style overrides, merged over the theme's `savedMessagesStyles`.
+
+| | |
+| --- | --- |
+| Type | `DeepPartial` |
+| Default | — |
+
+See [Styling](#styling).
---
diff --git a/ui-kit/react-native/threaded-messages-header.mdx b/ui-kit/react-native/threaded-messages-header.mdx
index dbe4e5314..f8a9b2138 100644
--- a/ui-kit/react-native/threaded-messages-header.mdx
+++ b/ui-kit/react-native/threaded-messages-header.mdx
@@ -159,6 +159,29 @@ function CustomTemplateDemo() {
---
+## Thread Subscription
+
+On React Native the subscription bell belongs to [CometChatMessageHeader](/ui-kit/react-native/message-header#thread-subscription) — the landed design places it in the thread screen's top bar rather than in the reply-count row.
+
+A thread screen usually renders both: the message header as the top bar, and this component beneath it for the parent message and reply count.
+
+```tsx lines
+import {
+ CometChatMessageHeader,
+ CometChatThreadHeader,
+} from "@cometchat/chat-uikit-react-native";
+
+// Top bar — `parentMessage` puts it in thread mode and renders the bell
+
+
+// Reply-count row — the parent message and its reply count
+
+```
+
+This component's own `TrailingView` replaces the trailing area of the reply-count bar. It is the escape hatch for putting your own control there — it does not host the subscription bell.
+
+See [CometChatMessageHeader → Thread Subscription](/ui-kit/react-native/message-header#thread-subscription) for the bell's props, and the [Thread Subscription guide](/ui-kit/react-native/guide-threaded-messages#thread-subscription) for the full feature.
+
## Next Steps