CometChatPinnedMessages component lists every message pinned in a conversation, newest pin first. Pins are conversation-wide — everyone in the chat sees the same list — so the panel is a shared, always-current view of what the conversation has singled out.
Overview
The Pinned Messages panel provides:- Conversation-scoped list: Pass either a
useror agroup; the panel fetches that conversation’s pins - Real message bubbles: Each row renders the actual message bubble, so media, polls, and formatted text look as they do in the chat
- Pinned-by attribution: Each row is labelled with who pinned it and when
- Inline unpin: A per-row unpin control, behind a confirmation dialog
- Row options: Save, Copy, Info, Translate, Report, and Message privately under a three-dot menu
- Message information: Opens over the panel, without leaving it — Info is self-contained, so it is not forwarded to the host
- System pins respected: A pin the app placed app-wide cannot be lifted by a member, so Unpin is withheld on those rows
- Live updates: Edits, deletions, reactions, and pin changes are reflected without a refetch
- Focus trap: Traps keyboard focus within the panel for modal-like behavior
Pin Message is gated by the
features.ux.messages.pinned.enabled app setting, which CometChat provisions server-side. Until it is on, CometChat.isPinMessageEnabled() resolves false and the pin surfaces do not render. See Enabling Pin and Save for the development override.Live Preview — a group conversation with several pinned messages, newest pin first.
Open in Storybook ↗
Basic Usage
Group Pinned Messages
One-on-One Pinned Messages
Passuser instead of group. The two are mutually exclusive — set exactly one.
Opening the Panel from the Message Header
CometChatMessageHeader can add a Pinned messages entry to its overflow menu. The header only asks for the panel — the host decides where it appears.
Handling Forwarded Options
Unpin, Save, Unsave, Copy, and Message Information are completed by the panel itself. Translate, Report, and Message privately need surfaces the panel does not own — a translation cache, a report dialog, another conversation — so they are handed to the host rather than half-built here. Message privately also firesCometChatUIEvents.ccOpenChat, so a host already listening for that receives both.
Filtering
Pass amessagesRequestBuilder to control which pinned messages are fetched — the page size, most commonly. 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.
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. Do not set a different conversation scope on the builder.Properties
Events
Behavior
Row Options
Options appear in a fixed order, andquickOptionsCount decides how many stay outside the ⋮:
The list is read-only in every other respect: opening it marks nothing as read, moves no unread count, and nothing here edits or deletes a message.
Permissions
There is no client-side role gate. Unpin is offered to every member and the server is the sole authority — a member without the permission still sees the option, the call is refused withERR_ACTION_NOT_ALLOWED, and the optimistic flip reverts with a toast.
Unpin is deliberately not restricted to whoever pinned the message either — anyone the server allows can remove any pin.
[hideUnpinMessageOption]="true" is the only thing that withholds Unpin from the panel, apart from a system pin. Set it yourself where your app already knows the viewer cannot unpin; the panel will not work that out on its own.System Pins
An app can pin a message itself, app-wide, rather than on behalf of a member. A system pin (pinnedBy === "app_system") belongs to no one, and the server refuses to lift it for any member — so Unpin is not offered on those rows at all, here or in the message list. Save is untouched: it is private to the viewer and has nothing to do with who pinned.
System pins are capped separately from member pins, through the features.ux.messages.pinned.system.limit app setting.
Confirmation
Unpinning asks for confirmation; pinning does not. Pinning is trivially reversible and a dialog for it would only be friction, whereas unpinning removes something the whole conversation can see.Rendering Large Lists
The pinned read is not cursor-paginated — the server ignoressentAt/id when filtering by pinned — so the panel fetches in one request (limit 100 unless messagesRequestBuilder says otherwise) and windows locally: it renders 30 rows at a time and extends the window as you scroll. A conversation with hundreds of pins does not pay to build every bubble up front.
Live Updates
The panel subscribes toCometChatPinSaveEvents, so a pin or unpin made anywhere — by another member, or by this user on another device — is reflected without a refetch. Edits, deletions, and reactions on a pinned message update its row in place.
Customization
CSS Variables
Accessibility
Keyboard Navigation
- Escape dismisses the topmost layer only: the information overlay first, then the confirmation dialog, then the panel itself
- Tab cycles within the panel; focus does not escape to the page behind it
- Enter / Space on a row activates it, as a click does
Focus Management
Focus is trapped on open and released on destroy, so the panel behaves as a modal surface while it is up.Screen Reader Support
- The panel is a labelled
region - Rows are exposed as buttons
- Loading, empty, and error states are announced via
role="status" - Decorative glyphs — pin markers, media icons, illustrations — are
aria-hidden
Related
- Pin and Save Messages — the feature guide, including how to enable it
- CometChatSavedMessages — the per-user counterpart
- CometChatMessageInformation — opened from a row’s Info option
- CometChatMessageList — where messages are pinned from