> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-feature-react-thread-subscription-pin-sa.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Pinned Messages

> Displays the messages pinned in a conversation, with quick unpin and per-message options.

<Accordion title="AI Integration Quick Reference">
  ```json theme={null}
  {
    "component": "CometChatPinnedMessages",
    "package": "@cometchat/chat-uikit-react",
    "import": "import { CometChatPinnedMessages } from \"@cometchat/chat-uikit-react\";",
    "description": "Displays the messages pinned in a conversation, scoped to a user or group, with quick unpin and per-message options.",
    "cssRootClass": ".cometchat-pinned-messages",
    "primaryOutput": {
      "prop": "onItemClick",
      "type": "(message: CometChat.BaseMessage) => void"
    },
    "props": {
      "data": {
        "user": {
          "type": "CometChat.User",
          "note": "The 1:1 conversation whose pins to show. Mutually exclusive with group."
        },
        "group": {
          "type": "CometChat.Group",
          "note": "The group conversation whose pins to show. Mutually exclusive with user."
        },
        "messagesRequestBuilder": {
          "type": "CometChat.MessagesRequestBuilder",
          "default": "undefined"
        },
        "quickOptionsCount": {
          "type": "number",
          "default": "1",
          "note": "How many inline quick actions to show on a row before overflow."
        },
        "textFormatters": {
          "type": "CometChatTextFormatter[]",
          "default": "undefined"
        }
      },
      "visibility": {
        "hideCloseButton": { "type": "boolean", "default": false },
        "hideCopyMessageOption": { "type": "boolean", "default": false },
        "hideMessageInfoOption": { "type": "boolean", "default": false },
        "hideUnpinMessageOption": { "type": "boolean", "default": false },
        "hideSaveMessageOption": { "type": "boolean", "default": false },
        "hideUnsaveMessageOption": { "type": "boolean", "default": false },
        "hideFlagMessageOption": { "type": "boolean", "default": false },
        "hideMessagePrivatelyOption": { "type": "boolean", "default": false },
        "hideTranslateMessageOption": { "type": "boolean", "default": false }
      },
      "callbacks": {
        "onItemClick": "(message: CometChat.BaseMessage) => void",
        "onClose": "() => void"
      },
      "viewSlots": {
        "itemView": "(message: CometChat.BaseMessage) => ReactNode",
        "headerView": "ReactNode",
        "emptyView": "ReactNode",
        "errorView": "ReactNode",
        "loadingView": "ReactNode"
      }
    },
    "events": {
      "emitted": [],
      "emittedNote": "The component itself publishes nothing, but the per-message actions it renders (via the shared message options) publish UI events such as ui:message/pin-changed and ui:message/save-changed that keep other surfaces in sync.",
      "received": [
        {
          "name": "message/pinned",
          "payload": "{ message }",
          "description": "Adds the message to the list (network-confirmed)"
        },
        {
          "name": "ui:message/pin-changed",
          "payload": "{ message, pinned }",
          "description": "Optimistic local flip: adds on pin, removes on unpin"
        },
        {
          "name": "message/unpinned",
          "payload": "{ message }",
          "description": "Removes the message from the list"
        },
        {
          "name": "ui:message/save-changed",
          "payload": "{ message, saved }",
          "description": "Refreshes the row so the Save/Unsave option and glyph update"
        }
      ]
    }
  }
  ```
</Accordion>

## Overview

`CometChatPinnedMessages` renders the messages pinned in a single conversation. Scope it to a `user` or a `group`, and it fetches that conversation's pins, keeps them in sync as messages are pinned and unpinned in real time, and surfaces per-message actions (unpin, save, copy, info, and more). It is typically mounted as a panel that opens from the [Message Header](/ui-kit/react/components/message-header)'s pinned-messages action.

<Info>
  **Live Preview** — interact with the default pinned messages panel.

  [Open in Storybook ↗](https://storybook.cometchat.io/react/?path=/story/components-messages-pinned-messages--default)
</Info>

<iframe src="https://storybook.cometchat.io/react/iframe.html?id=components-messages-pinned-messages--default&viewMode=story&shortcuts=false&singleStory=true" className="w-full rounded-xl" loading="lazy" style={{height: "600px", border: "1px solid #e0e0e0"}} title="CometChat Pinned Messages — Default" allow="clipboard-write" />

The component handles:

* Fetching the conversation's pinned messages
* Real-time updates when a message is pinned or unpinned
* An overflow menu of per-message options (unpin, save, copy, info, and more)
* Empty, loading, and error states

<Note>
  Pinning must be enabled for your app through the `features.ux.messages.pinned.enabled` app setting for pins to load. See [Core Features](/ui-kit/react/core-features#pin-and-save-messages).
</Note>

***

## Usage

### Flat API

Pass the `user` or `group` whose pins you want to show.

```tsx theme={null}
import { CometChat } from "@cometchat/chat-sdk-javascript";
import { CometChatPinnedMessages } from "@cometchat/chat-uikit-react";

function PinnedPanel({
  group,
  onClose,
}: {
  group: CometChat.Group;
  onClose: () => void;
}) {
  return <CometChatPinnedMessages group={group} onClose={onClose} />;
}
```

### Compound Composition

For full layout control, compose the sub-components under `Root`. Omit any sub-component to drop it.

```tsx theme={null}
import { CometChatPinnedMessages } from "@cometchat/chat-uikit-react";

<CometChatPinnedMessages.Root group={group} onClose={onClose}>
  <CometChatPinnedMessages.Header />
  <CometChatPinnedMessages.List />
  <CometChatPinnedMessages.EmptyState />
  <CometChatPinnedMessages.ErrorState />
  <CometChatPinnedMessages.LoadingState />
</CometChatPinnedMessages.Root>
```

### Opening from the Message Header

Wire the panel to the header's pinned-messages action with `onPinnedMessagesClicked`. See the [Pin & Save Messages guide](/ui-kit/react/guide-pin-and-save-messages) for the full screen.

```tsx theme={null}
import { useState } from "react";
import {
  CometChatMessageHeader,
  CometChatPinnedMessages,
} from "@cometchat/chat-uikit-react";

function ChatWithPins({ group }: { group: CometChat.Group }) {
  const [showPins, setShowPins] = useState(false);

  return (
    <>
      <CometChatMessageHeader
        group={group}
        onPinnedMessagesClicked={() => setShowPins(true)}
      />
      {/* ...message list + composer... */}
      {showPins && (
        <CometChatPinnedMessages group={group} onClose={() => setShowPins(false)} />
      )}
    </>
  );
}
```

***

## Filtering

Pass a `messagesRequestBuilder` to control which pinned messages are fetched — for example, to change the page size. Call `setPinned(true)` on the builder: it is what scopes the request to pinned messages, and without it the request is an ordinary history read.

```tsx theme={null}
import { CometChat } from "@cometchat/chat-sdk-javascript";
import { CometChatPinnedMessages } from "@cometchat/chat-uikit-react";

<CometChatPinnedMessages
  group={group}
  messagesRequestBuilder={
    new CometChat.MessagesRequestBuilder()
      .setPinned(true) // required — scopes the fetch to pinned messages
      .setLimit(30)
  }
/>
```

<Note>
  The component re-asserts `setPinned(true)` and the `user`/`group` conversation scope on whatever builder you pass, so those are safe even if you omit them — but keep `setPinned(true)` in your code to make the intent explicit. Don't set a different conversation scope on the builder.
</Note>

***

## Actions and Events

### Callback Props

| Prop          | Signature                                  | Fires when                                                     |
| ------------- | ------------------------------------------ | -------------------------------------------------------------- |
| `onItemClick` | `(message: CometChat.BaseMessage) => void` | A pinned row is clicked (e.g. jump to the message in the list) |
| `onClose`     | `() => void`                               | The close button is clicked                                    |

### Events

The component itself publishes nothing, but the per-message actions it renders (through the shared message options) publish UI events — such as `ui:message/pin-changed` and `ui:message/save-changed` — that keep other surfaces in sync.

It subscribes to the kit event bus and updates its list automatically. Each pin/save has two events: an optimistic `ui:` flip fired the moment the action succeeds locally, and the network-confirmed SDK event that follows:

| Event                                 | Payload               | Behavior                                                     |
| ------------------------------------- | --------------------- | ------------------------------------------------------------ |
| `ui:message/pin-changed`              | `{ message, pinned }` | Optimistic: adds on pin, removes on unpin                    |
| `message/pinned` / `message/unpinned` | `{ message }`         | Network-confirmed add / remove                               |
| `ui:message/save-changed`             | `{ message, saved }`  | Refreshes the row so the Save/Unsave option and glyph update |

See the [Event System](/ui-kit/react/event-system#pin-and-save) for the full list.

***

## Customization

### Per-message Options

Each pinned row exposes its actions in an overflow menu, with the first few surfaced inline as quick actions. Use the `hide*` props to trim the menu:

```tsx theme={null}
<CometChatPinnedMessages
  group={group}
  hideSaveMessageOption
  hideTranslateMessageOption
/>
```

Adjust how many actions appear inline (before the overflow menu) with `quickOptionsCount`:

```tsx theme={null}
<CometChatPinnedMessages group={group} quickOptionsCount={2} />
```

### View Props

Replace parts of the UI while keeping the component's behavior:

```tsx theme={null}
<CometChatPinnedMessages
  group={group}
  itemView={(message) => <MyPinnedRow message={message} />}
  emptyView={<div>Nothing pinned yet</div>}
/>
```

| Slot          | Type                                            | Replaces          |
| ------------- | ----------------------------------------------- | ----------------- |
| `itemView`    | `(message: CometChat.BaseMessage) => ReactNode` | A pinned row      |
| `headerView`  | `ReactNode`                                     | The panel header  |
| `emptyView`   | `ReactNode`                                     | The empty state   |
| `errorView`   | `ReactNode`                                     | The error state   |
| `loadingView` | `ReactNode`                                     | The loading state |

### Compound Composition

Use sub-components for full layout control:

| Sub-component  | Description                              | Flat API equivalent |
| -------------- | ---------------------------------------- | ------------------- |
| `Root`         | Context provider and container           | —                   |
| `Header`       | Panel header with title and close button | `headerView`        |
| `List`         | The scrollable list of pinned rows       | —                   |
| `Item`         | A single pinned row (`message`, `index`) | `itemView`          |
| `EmptyState`   | Shown when nothing is pinned             | `emptyView`         |
| `ErrorState`   | Shown on a load error                    | `errorView`         |
| `LoadingState` | Shown while loading                      | `loadingView`       |

### CSS Styling

Override design tokens on the component selector:

```css theme={null}
.cometchat-pinned-messages {
  --cometchat-background-color-01: #ffffff;
  --cometchat-text-color-primary: #141414;
}
```

***

## Props

Provide either `user` or `group` (not both). All other props are optional.

<Note>
  View slot props (`itemView`, `headerView`, `emptyView`, `errorView`, `loadingView`) are convenience props on the flat API. In compound composition mode, use the corresponding sub-components directly.
</Note>

***

### user

The 1:1 conversation whose pinned messages to show. Mutually exclusive with `group`.

|         |                  |
| ------- | ---------------- |
| Type    | `CometChat.User` |
| Default | `undefined`      |

***

### group

The group conversation whose pinned messages to show. Mutually exclusive with `user`.

|         |                   |
| ------- | ----------------- |
| Type    | `CometChat.Group` |
| Default | `undefined`       |

***

### messagesRequestBuilder

Customize the request used to fetch pinned messages (for example, the page size).

|         |                                    |
| ------- | ---------------------------------- |
| Type    | `CometChat.MessagesRequestBuilder` |
| Default | `undefined`                        |

***

### quickOptionsCount

How many per-message actions to show inline on a row before the rest collapse into the overflow menu.

|         |          |
| ------- | -------- |
| Type    | `number` |
| Default | `1`      |

***

### textFormatters

Text formatters applied when rendering the pinned message previews. See [Text Formatters](/ui-kit/react/plugins/text-formatters).

|         |                            |
| ------- | -------------------------- |
| Type    | `CometChatTextFormatter[]` |
| Default | `undefined`                |

***

### hideCloseButton

Hide the close button in the panel header.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideUnpinMessageOption

Remove the unpin action from the per-message options.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideSaveMessageOption / hideUnsaveMessageOption

Remove the save / unsave actions from the per-message options.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideCopyMessageOption

Remove the copy action from the per-message options.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideMessageInfoOption

Remove the message-info action from the per-message options.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideFlagMessageOption

Remove the flag action from the per-message options.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideMessagePrivatelyOption

Remove the "message privately" action from the per-message options.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### hideTranslateMessageOption

Remove the translate action from the per-message options.

|         |           |
| ------- | --------- |
| Type    | `boolean` |
| Default | `false`   |

***

### onItemClick

Callback when a pinned row is clicked.

|         |                                            |
| ------- | ------------------------------------------ |
| Type    | `(message: CometChat.BaseMessage) => void` |
| Default | `undefined`                                |

***

### onClose

Callback when the close button is clicked.

|         |              |
| ------- | ------------ |
| Type    | `() => void` |
| Default | `undefined`  |

***

### className

Additional CSS class for the root element.

|         |             |
| ------- | ----------- |
| Type    | `string`    |
| Default | `undefined` |

***

## CSS Selectors

| Target                 | Selector                                           |
| ---------------------- | -------------------------------------------------- |
| Root container         | `.cometchat-pinned-messages`                       |
| Header                 | `.cometchat-pinned-messages__header`               |
| Header title           | `.cometchat-pinned-messages__header-title`         |
| Header close button    | `.cometchat-pinned-messages__header-close`         |
| List                   | `.cometchat-pinned-messages__list`                 |
| Row                    | `.cometchat-pinned-messages__item`                 |
| Row header (pinned-by) | `.cometchat-pinned-messages__row-header`           |
| Row header name        | `.cometchat-pinned-messages__row-header-name`      |
| Empty state            | `.cometchat-pinned-messages__empty`                |
| Empty title            | `.cometchat-pinned-messages__empty-title`          |
| Empty subtitle         | `.cometchat-pinned-messages__empty-subtitle`       |
| Error state            | `.cometchat-pinned-messages__error`                |
| Loading shimmer        | `.cometchat-pinned-messages__shimmer`              |
| Message-info overlay   | `.cometchat-pinned-messages__message-info-overlay` |
| Message-info panel     | `.cometchat-pinned-messages__message-info-panel`   |

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Pin & Save Messages Guide" icon="thumbtack" href="/ui-kit/react/guide-pin-and-save-messages">
    Build a full pin/save screen end to end
  </Card>

  <Card title="Saved Messages" icon="bookmark" href="/ui-kit/react/components/saved-messages">
    The user's saved messages across conversations
  </Card>

  <Card title="Message Header" icon="heading" href="/ui-kit/react/components/message-header">
    Open the pinned-messages panel from the header
  </Card>

  <Card title="Message List" icon="comments" href="/ui-kit/react/components/message-list">
    Toggle the pin/unpin message options
  </Card>
</CardGroup>
