Goal
By the end of this guide you will have a chat interface with a search panel that lets users find messages in a conversation by keyword and scroll to a selected result — using the built-in CometChatSearch component instead of building your own search UI.
CometChatSearch already handles the input, debouncing, SDK queries, result rendering, pagination, loading/empty/error states, and keyword highlighting — so you only wire it to your message list.
Prerequisites
- Completed the Integration Guide
- A running
CometChatProvider setup with valid credentials
- An existing chat screen using
CometChatMessageList and CometChatMessageHeader
Components Used
| Component | Purpose |
|---|
CometChatSearch | Built-in search panel — input, message queries, result list, and states |
CometChatMessageList | Displays messages and supports goToMessageId for scrolling to a result |
CometChatMessageHeader | Header with a search trigger button |
CometChatConversations | Sidebar for switching conversations |
Step 1: Set up the chat layout with search state
Start with a full chat layout — a conversations sidebar, message panel, and state to control the search panel visibility and the message to jump to.
File: App.tsx
import { useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import {
CometChatProvider,
CometChatConversations,
CometChatMessageList,
CometChatMessageComposer,
CometChatMessageHeader,
CometChatSearch,
type CometChatSearchMessageClickEvent,
} from "@cometchat/chat-uikit-react";
function ChatWithSearch() {
const [user, setUser] = useState<CometChat.User | null>(null);
const [group, setGroup] = useState<CometChat.Group | null>(null);
const [showSearch, setShowSearch] = useState(false);
const [goToMessageId, setGoToMessageId] = useState<number | undefined>(undefined);
function handleConversationClick(conversation: CometChat.Conversation) {
setShowSearch(false);
setGoToMessageId(undefined);
const entity = conversation.getConversationWith();
if (entity instanceof CometChat.User) {
setUser(entity);
setGroup(null);
} else if (entity instanceof CometChat.Group) {
setGroup(entity);
setUser(null);
}
}
// Fired by CometChatSearch when a message result is clicked
function handleMessageClick(event: CometChatSearchMessageClickEvent) {
setGoToMessageId(event.message.getId());
}
return (
<div style={{ display: "flex", height: "100vh" }}>
{/* Conversations sidebar */}
<div style={{ width: "300px", borderRight: "1px solid #e0e0e0" }}>
<CometChatConversations onItemClick={handleConversationClick} />
</div>
{/* Main message panel */}
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
{(user || group) && (
<>
<CometChatMessageHeader
user={user ?? undefined}
group={group ?? undefined}
auxiliaryButtonView={
<button
onClick={() => setShowSearch((prev) => !prev)}
aria-label="Search messages"
style={{ background: "none", border: "none", cursor: "pointer", fontSize: "18px" }}
>
🔍
</button>
}
/>
<div style={{ flex: 1, overflow: "hidden" }}>
<CometChatMessageList
user={user ?? undefined}
group={group ?? undefined}
goToMessageId={goToMessageId}
/>
</div>
<CometChatMessageComposer user={user ?? undefined} group={group ?? undefined} />
</>
)}
</div>
{/* Built-in search panel, scoped to the open conversation */}
{showSearch && (user || group) && (
<div style={{ width: "350px", borderLeft: "1px solid #e0e0e0" }}>
<CometChatSearch
searchIn={["messages"]}
uid={user?.getUid()}
guid={group?.getGuid()}
onMessageClicked={handleMessageClick}
onBack={() => setShowSearch(false)}
/>
</div>
)}
</div>
);
}
function App() {
return (
<CometChatProvider>
<ChatWithSearch />
</CometChatProvider>
);
}
export default App;
Step 2: Scope CometChatSearch to the conversation
CometChatSearch is a complete, self-contained search panel — there’s no custom input or result list to build. A few props tailor it to in-conversation message search:
<CometChatSearch
searchIn={["messages"]}
uid={user?.getUid()}
guid={group?.getGuid()}
onMessageClicked={handleMessageClick}
onBack={() => setShowSearch(false)}
/>
| Prop | What it does |
|---|
searchIn={["messages"]} | Shows only message results (omit it to also search conversations) |
uid / guid | Scopes the search to a single user or group conversation. Pass whichever matches the open chat |
onMessageClicked | Fired when a result is tapped. The event payload is { message, searchKeyword } |
onBack | Fired when the back button is clicked — use it to close the panel |
The component handles the search input, debouncing, SDK queries, pagination, and the loading/empty/error states internally. For the full prop list and customization (filter chips, custom result item views, request builders), see the Search component reference.
Step 3: Navigate to a selected search result
When a result is clicked, onMessageClicked gives you the selected message. Pass its ID to CometChatMessageList via the goToMessageId prop — the list scrolls to the matching message and highlights it.
function handleMessageClick(event: CometChatSearchMessageClickEvent) {
setGoToMessageId(event.message.getId());
}
<CometChatMessageList
user={user ?? undefined}
group={group ?? undefined}
goToMessageId={goToMessageId}
/>
Reset goToMessageId to undefined when switching conversations (as in handleConversationClick above) so the list doesn’t try to jump to a message ID from a previous chat.
Next Steps
- Search — full
CometChatSearch reference: filters, scopes, custom result views, and request builders
- Message List — configure message rendering and scroll behavior
- Message Header — customize header actions and auxiliary views
- Threaded Messages — add threaded replies to your chat