Ground truth: the per-platform UI Kit customization systems (theme objects / CSS vars, message templates, text formatters) verified against the installed kit. (Official docs linked below.) Verify symbols against the installed package/source before relying on them.
Companion skills: cometchat-components provides the component
catalog (what exists); this skill provides the customization workflow
(how to modify what exists). Use cometchat-components to look up
component names and props, then use this skill to plan and execute
the customization. For any pattern not covered below, the docs MCP
at cometchat-docs is the source of truth — query it before
generating any code.
Use this skill when
The user has already run /cometchat (or invoked the cometchat skill via their agent's mechanism — keyword "cometchat" or "integrate chat" works in most agents) (Phase A complete — there's a
working integration with .cometchat/state.json) and wants to change
how a component looks or behaves beyond what the CLI's deterministic
commands handle.
Trigger phrases:
- "customize the message list"
- "filter the conversations to only show X"
- "change the message bubble color/shape/layout"
- "add a custom header above the chat"
- "subscribe to message-received events"
- "show a custom loading state"
- "add a custom action to the message options menu"
- "I want to inject my own UI into CometChatX"
/cometchat customize
Do not use this skill when
- The user wants to enable a packaged feature (calls, polls, AI smart
replies, etc.) → use
cometchat-features instead
- The user wants to change theme tokens (primary color, font,
border radius) → use
cometchat-theming instead (CSS-variable
overrides written directly into the project — there is no theming CLI)
- The user wants to start a new integration → use the
cometchat
dispatcher skill to run Phase A first
- The user wants to fix something broken → use
cometchat-troubleshooting and run cometchat doctor
Docs MCP contract
This skill is fundamentally docs-driven — every customization
question requires a fact (prop name, callback signature, builder method,
event topic, CSS selector) that lives in the canonical CometChat docs,
not in this skill's text. Embedding examples here would create drift
the moment the SDK changes.
The canonical CometChat docs are the source of truth for this skill. The
docs MCP at cometchat-docs is the best way to query them when
available, but it is not a hard requirement — fall back to the public
docs site for any agent without it. The docs cover:
- Component prop tables (every component, every prop, every default)
- Custom view slots:
headerView, subtitleView, tailView,
optionsView, bubbleView, emptyView, loadingView, errorView
(which components support which slots — verified against the v6 React
kit: the list components CometChatConversations/MessageList/Users/
Groups use emptyView/loadingView/errorView, not the
*StateView form; only CometChatNotificationFeed uses
emptyStateView/loadingStateView/errorStateView)
- Message template overrides (
CometChatMessageTemplate.type,
category, contentView, headerView, footerView)
- Request builders for filtering data:
ConversationsRequestBuilder,
MessagesRequestBuilder, UsersRequestBuilder, GroupsRequestBuilder,
CallLogsRequestBuilder and their methods
- SDK events:
CometChatMessageEvents, CometChatUserEvents,
CometChatGroupEvents, CometChatCallEvents, CometChatUIEvents
and the topic names
- CSS selectors for component-level styling overrides
(
.cometchat-message-bubble-incoming, .cometchat-conversations-header,
etc.)
Hard rules:
- Look up the docs before generating any customization code. Never
invent prop names, builder methods, event topics, or CSS classes from
training-data memory. Use whichever lookup path is available, in order:
- (a) docs MCP — query the
cometchat-docs MCP tool if your agent
has it. Richest path.
- (b) install the MCP, if your agent supports it — Claude Code:
claude mcp add --transport http cometchat-docs https://www.cometchat.com/docs/mcp. Other agents (Cursor, Codex,
Cline, …) configure MCP their own way, or not at all — do NOT block.
- (c) fetch/search the public docs — same content at the canonical
URLs below, or web-search
site:cometchat.com/docs. Universal
fallback; never STOP and dead-end the user when the MCP isn't
installed — fall through to (c).
- Prefer composition (custom view props) over CSS overrides when
both are options — composition is more stable across SDK versions.
- Canonical reference URLs:
Steps
Step 1 — Verify Phase A is done
npx @cometchat/skills-cli info --json
If integrated is false, stop and tell the user to run
/cometchat first to create the base integration. Customization
modifies an existing integration; it doesn't create one.
Note the framework, experience, files_owned, and applied_features
from the response — you'll need them in the next steps.
Step 2 — Four-tier discovery: existing-component prop, new component, stylesheet, sample app
START HERE: Read the component catalog at
references/component-catalog.md (in this skill's directory). It has
the canonical list of all 88 exported symbols, all 14 sample-app
patterns, and a 40-row task→component lookup table. If the user's
request maps to an entry in the catalog, use that entry directly —
skip the rest of this step.
If the catalog doesn't have a match (or you need prop-level detail),
walk these FOUR discovery checks in this exact order:
- Existing-component prop check (2a): does a component the
integration ALREADY mounts have a prop that does what the user is
asking for? The kit follows a "props over components" philosophy
— most additions are props on existing components, not new
components. This check goes FIRST.
- New-component check (2b): if 2a turned up nothing, is there a
built-in
CometChat<X> component in @cometchat/chat-uikit-react's
exports?
- Stylesheet check (2c): is there a
--cometchat-<x> CSS
variable for any styling you'd write?
- Sample app check (2d): is there a reference implementation in
the sample app at
github.com/cometchat/cometchat-uikit-react/tree/v6/sample-app/src/components
for the user's pattern?
The CometChat React UI Kit ships FOUR things, not one:
- A "props over components" API where most features (search bar,
filters, custom views, click handlers, disable flags) are PROPS on
existing components — NOT new components
- 60+ named React components in the npm package
- A 200+ CSS variable system at
@cometchat/chat-uikit-react/css-variables.css
- A reference sample app on GitHub with implementations for common
chat UX patterns (user/group details, threaded messages layout,
top-level home layout, multi-tab chat, notifications, new chat
dialog, etc.) that combine multiple kit components but aren't
shipped as single named exports
Critical: the docs MCP does NOT index the sample app. When the MCP
says "no CometChat<X> component exists", that only covers the npm
package — you must still check the sample app via GitHub before
concluding the user needs hand-rolled code.
Hand-rolling something the kit, the variable system, OR the sample
app already provides means missing the kit's theming, accessibility,
i18n, error handling, and every future SDK update.
2a. Existing-component prop check (do this FIRST)
Most chat features are already props on the components you have.
A user asking for "add search", "filter conversations", "custom empty
state", or "click handler on a message" is almost always asking for a
prop, not a new component or custom code.
Process:
- List the CometChat components currently mounted in the
integration. Read the integration's owned files (from
state.json) and grep for <CometChat JSX usage:grep -hoE '<CometChat[A-Z][a-zA-Z]*' \
$(jq -r '.files_owned[]' .cometchat/state.json 2>/dev/null) \
2>/dev/null | sort -u
- Query the docs MCP for the props of each mounted component:
"CometChatConversations props"
"CometChatMessageList props"
"CometChatMessageHeader props"
"CometChatMessageComposer props"
- Look for a prop that maps to the user's intent. Common
mappings:
| User asks for |
Likely prop on which component |
| Search bar / "add search" |
showSearchBar on CometChatConversations (or onSearchBarClicked to swap in <CometChatSearch> for advanced dual-scope search) |
| Filter conversations |
conversationsRequestBuilder on CometChatConversations |
| Filter messages |
messagesRequestBuilder on CometChatMessageList |
| Filter users / groups |
usersRequestBuilder / groupsRequestBuilder |
| Custom empty state |
emptyView on the list components (Conversations/MessageList/Users/Groups); emptyStateView only on CometChatNotificationFeed |
| Custom error UI |
errorView (list components); errorStateView on CometChatNotificationFeed |
| Custom loading UI |
loadingView (list components); loadingStateView on CometChatNotificationFeed |
| Custom header above the list |
headerView |
| Custom message bubble |
templates prop on CometChatMessageList (not a custom bubble component) |
| Click handler on item / message / search bar / back button |
onItemClick, onMessageClick, onBack, onSearchBarClicked |
| Hide / disable a sub-feature |
disable* boolean props (e.g. disableTyping, disableReactions) |
| Custom subtitle / status / timestamp |
subtitleView, statusView, timestampView |
| Show / hide receipts |
hideReceipts |
| Selection mode |
selectionMode on list components |
If you find a matching prop, just add the prop and stop. No new
components. No custom CSS. No new files. Surface to the user: "The
<X> you already have supports this via the <propName> prop. Adding
that single prop."
If 2a turns up nothing, proceed to 2b.
2b. New-component check (do this only if 2a turned up nothing)
Common requests that look like "customization" but are actually
"use the existing component":
| User asks for |
Use this built-in component |
| Threaded replies / "wire up threads" |
CometChatThreadHeader + scope a CometChatMessageList and CometChatMessageComposer with parentMessageId |
| Group members panel / "list group members" |
CometChatGroupMembers |
| Add members to a group |
CometChatAddMembers |
| Transfer group ownership |
CometChatTransferOwnership |
| Banned users management |
CometChatBannedMembers |
| Block/unblock users panel |
CometChatBlockedUsers |
| New chat / "start a new conversation" dialog |
CometChatNewChat |
| Create new group dialog |
CometChatCreateGroup |
| User / group details panel |
CometChatDetails |
| Mentions popover in composer |
CometChatMentionsFormatter (already wired into the composer) |
| Voice / video call buttons in header |
CometChatCallButtons |
| Outgoing call screen |
CometChatOutgoingCall |
| Incoming call notification |
CometChatIncomingCall |
| Ongoing call UI |
CometChatOngoingCall |
| Call logs list |
CometChatCallLogs |
| Reactions on messages |
Already built into CometChatMessageList — check if it's just disabled |
| Message bubble customization |
Use the templates prop on CometChatMessageList, not a custom bubble component |
⚠️ Not every row above is a kit export. CometChatAddMembers, CometChatTransferOwnership, CometChatBannedMembers, CometChatBlockedUsers, CometChatNewChat, CometChatCreateGroup, and CometChatDetails are sample-app components, NOT @cometchat/chat-uikit-react v6 exports — importing <CometChatTransferOwnership/> etc. is an unresolved-import build error. Build these by copying the sample-app implementation (§2d), do not import them from the package. The genuinely package-exported entries in this table are: CometChatThreadHeader, CometChatGroupMembers, CometChatMentionsFormatter, CometChatCallButtons, CometChatOutgoingCall, CometChatIncomingCall, CometChatOngoingCall, CometChatCallLogs. Always grep the installed package's exports (next step) before emitting any of these.
Search strategies, in this order:
- Query the docs MCP with the user's intent in plain English.
Examples:
"thread reply UI react ui kit" → finds CometChatThreadHeader
"new chat dialog" → finds CometChatNewChat
"group transfer ownership" → finds CometChatTransferOwnership
"block user list" → finds CometChatBlockedUsers
- Grep the user's installed package for matching exports:
grep -E "^export.*CometChat[A-Z][a-zA-Z]+" \
node_modules/@cometchat/chat-uikit-react/dist/index.d.ts \
2>/dev/null | head -50
- Browse the v6 components reference at
https://www.cometchat.com/docs/ui-kit/react/components-overview
If you find a built-in component that matches, use it as-is.
Surface to the user: "The kit already ships CometChat<X> for this.
I'll wire it up directly."
2c. Stylesheet check (do this even when you DO need custom layout glue)
Even when you have to write some CSS for layout glue (positioning a
panel, sizing a container, wiring up the height chain that
.cometchat-message-list requires), never hand-pick colors, fonts,
borders, spacings, or radii from your head. The kit ships a
canonical CSS variable system. Use it.
The rule:
- ✅ OK: custom CSS for layout glue (positioning, sizing, flex
containers, the height chain). Example:
.thread-wrapper { width: 400px; height: 100vh; display: flex; flex-direction: column; }
- ✅ OK: custom CSS that consumes kit variables. Example:
.thread-wrapper { border-left: 1px solid var(--cometchat-border-color-light); background: var(--cometchat-background-color-01); }
- ❌ NOT OK: custom CSS for any header / button / icon / panel /
badge / divider that the kit already provides as a component.
Example: a hand-rolled
.thread-header + .thread-close button when
CometChatThreadHeader exists.
- ❌ NOT OK: hardcoded colors / fonts / borders / radii / spacings
that don't reference the
--cometchat-* variables. Example:
border: 1px solid #E8E8E8 instead of
border: 1px solid var(--cometchat-border-color-light).
Discovery commands for the variable system:
# List every --cometchat-* variable the kit defines
grep -oE '\-\-cometchat-[a-z0-9-]+' \
node_modules/@cometchat/chat-uikit-react/css-variables.css \
2>/dev/null | sort -u | head -60
# Or search for a specific token category
grep -E '\-\-cometchat-(border|background|text|primary|font)' \
node_modules/@cometchat/chat-uikit-react/css-variables.css \
2>/dev/null | head -40
Common variable categories (query the docs MCP for the canonical
list — these change between SDK versions):
| Category |
Example variables |
| Brand colors |
--cometchat-primary-color, --cometchat-error-color, --cometchat-success-color |
| Backgrounds |
--cometchat-background-color-01 (white), --cometchat-background-color-02, --cometchat-background-color-03 (light grey) |
| Text |
--cometchat-text-color-primary, --cometchat-text-color-secondary, --cometchat-text-color-tertiary |
| Borders |
--cometchat-border-color-light, --cometchat-border-color-default, --cometchat-border-color-dark |
| Radii |
--cometchat-radius-1, --cometchat-radius-2, --cometchat-radius-3, --cometchat-radius-max |
| Fonts |
--cometchat-font-heading1-bold, --cometchat-font-heading4-medium, --cometchat-font-body-regular, --cometchat-font-caption2-regular |
| Spacing |
--cometchat-spacing-1 through --cometchat-spacing-10 |
| Shadows |
--cometchat-shadow-1, --cometchat-shadow-2, --cometchat-shadow-3 |
2d. Sample app reference check (do this when 2a + 2b turned up nothing)
If 2b didn't find a CometChat<X> component for the user's request,
don't immediately conclude they need custom code. The kit ships a
reference sample app at:
https://github.com/cometchat/cometchat-uikit-react/tree/v6/sample-app/src/components
with implementations for common chat UX patterns that combine multiple
kit components but aren't shipped as single named exports. Examples
that look like "missing components" but are in the sample app:
| User asks for |
Sample app reference path |
| User / group details panel |
sample-app/src/components/CometChatDetails/CometChatUserDetails.tsx (group details is inline in CometChatHome.tsx's SideComponentGroup) |
| Threaded messages panel layout |
sample-app/src/components/CometChatDetails/CometChatThreadedMessages.tsx |
| Top-level chat layout (left pane + main + side rail) |
sample-app/src/components/CometChatHome/CometChatHome.tsx |
| Multi-tab chat (Chats / Calls / Users / Groups) |
sample-app/src/components/CometChatSelector/CometChatTabs.tsx |
| New conversation dialog with user/group picker |
Inline in CometChatHome.tsx as CometChatNewChatView (CSS: sample-app/src/styles/CometChatNewChat/CometChatNewChatView.css) |
| Search view (conversations + messages) |
sample-app/src/components/CometChatSearchView/ |
| Call log details / history / recordings |
sample-app/src/components/CometChatCallLog/ (5 sub-files: Details, History, Info, Participants, Recordings) |
| App state / active-chat React context |
sample-app/src/context/AppContext.jsx + appReducer.ts |
| Group ownership transfer modal |
sample-app/src/components/CometChatTransferOwnership/ |
These patterns include matching CSS at
sample-app/src/styles/<ComponentName>/ using BEM-style class names
that are already wired to the kit's CSS variable system.
Discovery commands:
# List the sample app's components directory via the GitHub API
curl -s "https://api.github.com/repos/cometchat/cometchat-uikit-react/contents/sample-app/src/components?ref=v6" \
| grep -oE '"name":\s*"[^"]+"' | head -30
# Fetch a specific component file directly
curl -s "https://raw.githubusercontent.com/cometchat/cometchat-uikit-react/v6/sample-app/src/components/CometChatDetails/CometChatUserDetails.tsx"
# Fetch its matching stylesheet
curl -s "https://raw.githubusercontent.com/cometchat/cometchat-uikit-react/v6/sample-app/src/styles/CometChatDetails/CometChatUserDetails.css"
You can also use WebFetch on the URLs above. The docs MCP does NOT
index the sample app — you must fetch it from GitHub directly.
If you find a matching reference implementation:
- Read BOTH the
.tsx file AND its matching .css file (at
sample-app/src/styles/<ComponentName>/)
- Mirror the sample app's file/folder structure in the user's project,
e.g.
src/cometchat/CometChatDetails/CometChatUserDetails.tsx plus
src/cometchat/CometChatDetails/CometChatDetails.css
- Match the exact BEM class names from the sample
(
.cometchat-user-details__header,
.cometchat-user-details__content-avatar, etc.) — they're already
integrated with the kit's CSS variable system
- Strip the sample app's local dependencies that the user's project
doesn't have:
useContext(AppContext) → inline the values
getLocalizedString(...) → inline the English strings
cometchat-resources/ SVG icons → use Unicode equivalents or
strip them
- Tell the user: "The kit doesn't export this as a single component,
but the official sample app has the reference implementation at
cometchat/cometchat-uikit-react/v6/sample-app/.../CometChat<X>.
I'm adapting it to your project."
2e. After discovery — decide what to do
In strict order, take the FIRST option that applies:
- An existing component prop matches (2a): add the prop. Done.
No new files. Most chat features land here.
- A new component matches (2b) AND has its own styling: use the
component as-is. Zero custom CSS.
- A new component matches (2b) but you need layout glue: use the
component; write minimal layout-only CSS that consumes
--cometchat-* variables (per 2c).
- Sample app has a reference implementation (2d): adapt the
sample app pattern, mirroring its file structure and BEM class
names.
- None of the above: then (and only then) proceed to Step 3 to
classify the request as a true customization.
Step 3 — Classify the customization
Read the user's request and place it into one of these buckets. The
right approach is different per bucket:
| Bucket |
Examples |
Approach |
| A. Custom view slot |
"add a custom header above the conversation list", "show a custom empty state", "render messages with my own bubble" |
Use the corresponding *View prop (headerView, emptyView, bubbleView, etc.) — look up which prop the target component supports (list components use emptyView/loadingView/errorView; CometChatNotificationFeed uses the *StateView form) |
| B. Filter / pagination |
"only show conversations with VIP users", "load 10 messages at a time", "show only joined groups" |
Use the corresponding RequestBuilder (ConversationsRequestBuilder.setTags, setLimit, setUserAndGroupTags, etc.) — query the MCP for the builder methods |
| C. Action / callback |
"do X when a user clicks a conversation", "intercept message send", "log every search" |
Use the corresponding on* callback prop (onItemClick, onSendButtonClick, onSearch, etc.) — query the MCP for the callback signature |
| D. Event subscription |
"show a toast when a new message arrives", "update my unread count when someone reads a message", "track typing indicators" |
Subscribe to the corresponding CometChat*Events topic (CometChatMessageEvents.ccMessageSent, ccMessageRead, CometChatUserEvents.ccUserOnline, etc.) — query the MCP for the event topic |
| E. Component-level CSS |
"make incoming bubbles green", "hide the conversation timestamps", "compact the message list spacing" |
Add a CSS rule under .cometchat <selector> in the integration's global stylesheet — query the MCP for the right selector class. NEVER invent class names; the SDK's selectors are namespaced and prefix-protected. |
| F. Component composition |
"wrap CometChatConversations with my own search bar", "render two CometChatGroups side by side", "embed CometChatMessageList inside my own card layout" |
Standard React composition. The CometChat components are React components — use them like any other component. Query the MCP for which props are required vs optional. |
Message templates / options / composer attachments → use the verified recipes in cometchat-features §Type 5, not a hand-rolled bubbleView. Sending a custom message TYPE, overriding an existing type's bubble, adding a Forward-style message action, or adding a composer attachment all require the append-not-replace CometChatUIKit.getDataSource() merge (a bare templates=/attachmentOptions= array silently wipes the built-ins — ENG-35706). §Type 5 has the copy-ready, tsc-verified code.
If the user's request doesn't fit any bucket, ask them to clarify —
don't guess. Customization is the place where ambiguous requests
produce wrong code most often.
Step 4 — Query the docs MCP for the canonical pattern (only if Step 2 turned up nothing)
Once you've classified the request, query the docs MCP with a specific
search:
| Bucket |
MCP query example |
| A. Custom view slot |
"headerView prop CometChatConversations" |
| B. Filter / pagination |
"ConversationsRequestBuilder methods setTags" |
| C. Action / callback |
"CometChatMessageList onMessageClick callback signature" |
| D. Event subscription |
"CometChatMessageEvents ccMessageSent subscribe" |
| E. Component-level CSS |
"CSS selector cometchat-message-bubble-incoming" |
| F. Component composition |
"CometChatConversations props required" |
The MCP returns canonical, current docs. Read them BEFORE writing any
code. If multiple results come back, prefer the React UI Kit v6 result
over older versions.
Step 5 — Identify the file to modify
Use the framework + experience you noted in Step 1 to find the right
file. The integration's primary client file is conventional per
framework:
| Framework |
Primary client file |
| reactjs (Vite) |
src/App.tsx (renders the conversation list / messages) + src/cometchat/CometChatSelector.tsx (the selector) |
| nextjs (App Router) |
src/app/cometchat/CometChatNoSSR.tsx (renders the chat) + src/app/cometchat/CometChatSelector.tsx (the selector) |
| nextjs (Pages Router) |
src/cometchat/CometChatNoSSR.tsx + src/cometchat/CometChatSelector.tsx |
| react-router (v6 + v7) |
app/cometchat/CometChatNoSSR.tsx + app/cometchat/CometChatSelector.tsx |
| astro |
src/cometchat/ChatApp.tsx (the React island) + src/cometchat/CometChatSelector.tsx |
For CSS overrides (bucket E), the global stylesheet is:
- reactjs →
src/index.css
- nextjs (App Router) →
src/app/globals.css
- nextjs (Pages Router) →
src/styles/globals.css
- react-router →
app/app.css
- astro → inside
src/cometchat/ChatApp.tsx (NOT a global stylesheet)
These are also in state.json under files_owned if you need to verify.
Step 6 — Write the customization
Generate the code based on the docs MCP response from Step 4. Show the
user:
- What you're going to change (which file, which lines, the new
code)
- Why (which prop/builder/event the docs say to use)
- A preview of the diff (just the changed region, not the whole
file)
Wait for the user to confirm before writing. Customization edits
the integration's owned files — drift detection will show this on the
next cometchat info. The user should know.
If the user confirms, write the change. If they don't, surface what
they'd want to change and stop.
Step 7 — Verify
npx @cometchat/skills-cli verify --json
The 5 AST checks still apply to customized files. If anything fails,
surface verbatim and offer to revert.
npx @cometchat/skills-cli info --json
The customized file will now show as drifted (its checksum no longer
matches the original template). This is expected — it's the
explicit drift the user just asked for. Not a bug.
Step 8 — Tell the user what to do next
The dev server picks up React changes via HMR. Tell the user:
- Save the file (if their editor doesn't auto-save)
- Refresh the browser tab
- Test the customization
Then offer to do another customization OR to return to the framework
skill's Phase B menu.
Hard rules
- Always do the FOUR-tier discovery before adding any new component
or hand-rolled UI. The kit follows a "props over components"
philosophy and ships FOUR things, not one:
(0) props on already-mounted components for most features
(search bar, filters, custom views, click handlers, disable
flags) — check this FIRST,
(1) 60+ named React components in
@cometchat/chat-uikit-react,
(2) a 200+ CSS variable system in css-variables.css,
(3) a reference sample app at
github.com/cometchat/cometchat-uikit-react/tree/v6/sample-app/src/components
with implementations for common chat UX patterns that combine
multiple kit components but aren't shipped as single named
exports (user/group details panels, thread layouts, top-level
home layout, notifications, new chat dialog, etc.).
The docs MCP does NOT index the sample app — fetch it from GitHub
directly. Adding a new component when an existing one's prop would
do, or hand-rolling something the kit, the variable system, or the
sample app already provides, means missing the kit's theming, i18n,
accessibility, and every future SDK update. Step 2 (subsections 2a
- 2b + 2c + 2d) is mandatory — do NOT skip it. 2a
(existing-component prop check) goes FIRST because most features
are props on already-mounted components, not new components.
- Custom CSS is allowed ONLY for layout glue (positioning,
sizing, flex/grid containers, the height chain). Even there, never
hardcode colors / fonts / borders / radii / spacings — always
reference
--cometchat-* variables. Hand-rolled headers, buttons,
icons, panels, badges, dividers, etc. are NEVER OK if the kit
already provides them.
- Always query the docs MCP first for any prop, builder, event, or
CSS selector. Never invent SDK API from memory.
- Verify Phase A is done before customizing. This skill modifies
existing integration files; it does not create new ones.
- Show the user the change before writing. Customization is
user-side intent — they need visibility.
- Drift detection is expected after customization, not a bug.
The user's customizations live in
state.files_owned and will
show up in cometchat info as modified. That's correct.
- Prefer composition over CSS overrides when both are options —
composition is stable across SDK versions; CSS selectors are not.
- Never invent CSS class names — look them up in the docs. The SDK's
class prefix is
.cometchat- but the leaf names (-message-bubble-incoming,
-conversations-header, etc.) MUST come from the docs.
- Look up the docs via the best available path (see §2's lookup
contract): docs MCP if your agent has it → else fetch/web-search the
public docs at cometchat.com/docs. Never STOP just because the MCP
isn't installed — fall through to the public docs.
- Always use
npx @cometchat/skills-cli for any CLI commands.
What this skill does NOT do
- It does not write template files (that's
cometchat init)
- It does not enable packaged features (that's
cometchat-features
- It does not change theme tokens (that's
cometchat-theming —
CSS-variable overrides, no CLI)
- It does not fix broken integrations (that's
cometchat-troubleshooting + cometchat doctor)
- It does not add new components from scratch — it customizes
components that the integration already uses
For anything in the "does not" list, route the user to the right
skill/command instead of attempting it here.
Sound (in-app message + call sounds)
Sound is a customization sub-dimension. The UI Kit plays incoming/outgoing message + call sounds via CometChatSoundManager — mute it, swap custom audio, or play a specific sound. The full API + recipe lives in cometchat-theming (Sound section). Verify the access path against the installed kit before relying on it.
1---2name: cometchat-customization3description: Customize a CometChat React UI Kit integration beyond what `cometchat init` and `cometchat apply-feature` produce — custom message bubbles, custom header views, custom subtitle views, custom empty/loading states, custom action menus, request builder filters, event listeners, and component composition. Picks up where the framework skills end (after Phase A init succeeds).4license: "MIT"5compatibility: "Node.js >=18; @cometchat/chat-uikit-react ^6"6metadata:7 author: "CometChat"8 version: "3.0.0"9 tags: "cometchat react customization custom-view message-bubble header-view subtitle-view request-builder events"10---1112> **Ground truth:** the per-platform UI Kit customization systems (theme objects / CSS vars, message templates, text formatters) verified against the installed kit. (Official docs linked below.) Verify symbols against the installed package/source before relying on them.1314> **Companion skills:** `cometchat-components` provides the component15> catalog (what exists); this skill provides the customization workflow16> (how to modify what exists). Use `cometchat-components` to look up17> component names and props, then use this skill to plan and execute18> the customization. For any pattern not covered below, the docs MCP19> at `cometchat-docs` is the source of truth — query it before20> generating any code.2122## Use this skill when2324The user has already run `/cometchat` (or invoked the cometchat skill via their agent's mechanism — keyword "cometchat" or "integrate chat" works in most agents) (Phase A complete — there's a25working integration with `.cometchat/state.json`) and wants to **change26how a component looks or behaves** beyond what the CLI's deterministic27commands handle.2829Trigger phrases:30- "customize the message list"31- "filter the conversations to only show X"32- "change the message bubble color/shape/layout"33- "add a custom header above the chat"34- "subscribe to message-received events"35- "show a custom loading state"36- "add a custom action to the message options menu"37- "I want to inject my own UI into CometChatX"38- `/cometchat customize`3940## Do not use this skill when4142- The user wants to enable a **packaged feature** (calls, polls, AI smart43 replies, etc.) → use `cometchat-features` instead44- The user wants to change **theme tokens** (primary color, font,45 border radius) → use `cometchat-theming` instead (CSS-variable46 overrides written directly into the project — there is no theming CLI)47- The user wants to **start a new integration** → use the `cometchat`48 dispatcher skill to run Phase A first49- The user wants to **fix something broken** → use50 `cometchat-troubleshooting` and run `cometchat doctor`5152## Docs MCP contract5354This skill is **fundamentally docs-driven** — every customization55question requires a fact (prop name, callback signature, builder method,56event topic, CSS selector) that lives in the canonical CometChat docs,57not in this skill's text. Embedding examples here would create drift58the moment the SDK changes.5960The canonical CometChat docs are the source of truth for this skill. The61docs MCP at `cometchat-docs` is the **best** way to query them when62available, but it is **not** a hard requirement — fall back to the public63docs site for any agent without it. The docs cover:6465- Component prop tables (every component, every prop, every default)66- Custom view slots: `headerView`, `subtitleView`, `tailView`,67 `optionsView`, `bubbleView`, `emptyView`, `loadingView`, `errorView`68 (which components support which slots — verified against the v6 React69 kit: the list components `CometChatConversations`/`MessageList`/`Users`/70 `Groups` use `emptyView`/`loadingView`/`errorView`, **not** the71 `*StateView` form; only `CometChatNotificationFeed` uses72 `emptyStateView`/`loadingStateView`/`errorStateView`)73- Message template overrides (`CometChatMessageTemplate.type`,74 `category`, `contentView`, `headerView`, `footerView`)75- Request builders for filtering data: `ConversationsRequestBuilder`,76 `MessagesRequestBuilder`, `UsersRequestBuilder`, `GroupsRequestBuilder`,77 `CallLogsRequestBuilder` and their methods78- SDK events: `CometChatMessageEvents`, `CometChatUserEvents`,79 `CometChatGroupEvents`, `CometChatCallEvents`, `CometChatUIEvents`80 and the topic names81- CSS selectors for component-level styling overrides82 (`.cometchat-message-bubble-incoming`, `.cometchat-conversations-header`,83 etc.)8485**Hard rules:**86871. **Look up the docs before generating any customization code.** Never88 invent prop names, builder methods, event topics, or CSS classes from89 training-data memory. Use whichever lookup path is available, in order:90 - **(a) docs MCP** — query the `cometchat-docs` MCP tool if your agent91 has it. Richest path.92 - **(b) install the MCP, if your agent supports it** — Claude Code:93 `claude mcp add --transport http cometchat-docs94 https://www.cometchat.com/docs/mcp`. Other agents (Cursor, Codex,95 Cline, …) configure MCP their own way, or not at all — do NOT block.96 - **(c) fetch/search the public docs** — same content at the canonical97 URLs below, or web-search `site:cometchat.com/docs`. Universal98 fallback; never STOP and dead-end the user when the MCP isn't99 installed — fall through to (c).1003. **Prefer composition (custom view props) over CSS overrides** when101 both are options — composition is more stable across SDK versions.1024. **Canonical reference URLs:**103 - Components overview: https://www.cometchat.com/docs/ui-kit/react/components-overview104 - Guides index: https://www.cometchat.com/docs/ui-kit/react/guide-overview — the 7 maintained task recipes (prefer these over hand-rolling): [Block/Unblock](https://www.cometchat.com/docs/ui-kit/react/guide-block-unblock-user) · [Call Log Details](https://www.cometchat.com/docs/ui-kit/react/guide-call-log-details) · [Group Management](https://www.cometchat.com/docs/ui-kit/react/guide-group-chat) · [Message Privately](https://www.cometchat.com/docs/ui-kit/react/guide-message-privately) · [New Chat](https://www.cometchat.com/docs/ui-kit/react/guide-new-chat) · [Search Messages](https://www.cometchat.com/docs/ui-kit/react/guide-search-messages) · [Threaded Messages](https://www.cometchat.com/docs/ui-kit/react/guide-threaded-messages)105 - **Custom message recipes** (verified, copy-ready): custom message TYPES, overriding an existing type's bubble (`bubbleView`/`contentView`), adding a Message Composer attachment option, and adding a message action like Forward — all live in **`cometchat-features` §Type 5** (append-not-replace via `CometChatUIKit.getDataSource()`). Route there for the actual code; this skill covers the custom-VIEW-slot props.106 - Theming + styling: https://www.cometchat.com/docs/ui-kit/react/theme107 - Events: https://www.cometchat.com/docs/ui-kit/react/events108 - Methods: https://www.cometchat.com/docs/ui-kit/react/methods109 - **Text formatters** (inline mention/URL/markdown/custom-token styling — `CometChatTextFormatter`): the four formatter guides `custom-text-formatter-guide`, `mentions-formatter-guide`, `url-formatter-guide`, `shortcut-formatter-guide` under `ui-kit/react/`. Recipe + the append-not-replace `getAllTextFormatters({})` pattern live in **`cometchat-features` §Type 5 → Text formatters**.110 - **Localization** (languages, custom strings, date/time formatting): handled by the dedicated **`cometchat-i18n`** skill (`CometChatLocalize`) — route there for any locale/string work; docs https://www.cometchat.com/docs/ui-kit/react/localize111112## Steps113114### Step 1 — Verify Phase A is done115116```bash117npx @cometchat/skills-cli info --json118```119120If `integrated` is `false`, **stop** and tell the user to run121`/cometchat` first to create the base integration. Customization122modifies an existing integration; it doesn't create one.123124Note the `framework`, `experience`, `files_owned`, and `applied_features`125from the response — you'll need them in the next steps.126127### Step 2 — Four-tier discovery: existing-component prop, new component, stylesheet, sample app128129> **START HERE:** Read the **component catalog** at130> `references/component-catalog.md` (in this skill's directory). It has131> the canonical list of all 88 exported symbols, all 14 sample-app132> patterns, and a 40-row task→component lookup table. If the user's133> request maps to an entry in the catalog, use that entry directly —134> skip the rest of this step.135136**If the catalog doesn't have a match (or you need prop-level detail),137walk these FOUR discovery checks in this exact order:**1381391. **Existing-component prop check (2a):** does a component the140 integration ALREADY mounts have a prop that does what the user is141 asking for? **The kit follows a "props over components" philosophy142 — most additions are props on existing components, not new143 components.** This check goes FIRST.1442. **New-component check (2b):** if 2a turned up nothing, is there a145 built-in `CometChat<X>` component in `@cometchat/chat-uikit-react`'s146 exports?1473. **Stylesheet check (2c):** is there a `--cometchat-<x>` CSS148 variable for any styling you'd write?1494. **Sample app check (2d):** is there a reference implementation in150 the sample app at151 `github.com/cometchat/cometchat-uikit-react/tree/v6/sample-app/src/components`152 for the user's pattern?153154The CometChat React UI Kit ships FOUR things, not one:155- A "props over components" API where most features (search bar,156 filters, custom views, click handlers, disable flags) are PROPS on157 existing components — NOT new components158- 60+ named React components in the npm package159- A 200+ CSS variable system at160 `@cometchat/chat-uikit-react/css-variables.css`161- A reference sample app on GitHub with implementations for common162 chat UX patterns (user/group details, threaded messages layout,163 top-level home layout, multi-tab chat, notifications, new chat164 dialog, etc.) that combine multiple kit components but aren't165 shipped as single named exports166167**Critical:** the docs MCP does NOT index the sample app. When the MCP168says *"no `CometChat<X>` component exists"*, that only covers the npm169package — you must still check the sample app via GitHub before170concluding the user needs hand-rolled code.171172Hand-rolling something the kit, the variable system, OR the sample173app already provides means missing the kit's theming, accessibility,174i18n, error handling, and every future SDK update.175176#### 2a. Existing-component prop check (do this FIRST)177178**Most chat features are already props on the components you have.**179A user asking for "add search", "filter conversations", "custom empty180state", or "click handler on a message" is almost always asking for a181prop, not a new component or custom code.182183**Process:**1841851. **List the CometChat components currently mounted in the186 integration.** Read the integration's owned files (from187 `state.json`) and grep for `<CometChat` JSX usage:188 ```bash189 grep -hoE '<CometChat[A-Z][a-zA-Z]*' \190 $(jq -r '.files_owned[]' .cometchat/state.json 2>/dev/null) \191 2>/dev/null | sort -u192 ```1932. **Query the docs MCP for the props of each mounted component:**194 - `"CometChatConversations props"`195 - `"CometChatMessageList props"`196 - `"CometChatMessageHeader props"`197 - `"CometChatMessageComposer props"`1983. **Look for a prop that maps to the user's intent.** Common199 mappings:200201| User asks for | Likely prop on which component |202|---|---|203| Search bar / "add search" | `showSearchBar` on `CometChatConversations` (or `onSearchBarClicked` to swap in `<CometChatSearch>` for advanced dual-scope search) |204| Filter conversations | `conversationsRequestBuilder` on `CometChatConversations` |205| Filter messages | `messagesRequestBuilder` on `CometChatMessageList` |206| Filter users / groups | `usersRequestBuilder` / `groupsRequestBuilder` |207| Custom empty state | `emptyView` on the list components (`Conversations`/`MessageList`/`Users`/`Groups`); `emptyStateView` only on `CometChatNotificationFeed` |208| Custom error UI | `errorView` (list components); `errorStateView` on `CometChatNotificationFeed` |209| Custom loading UI | `loadingView` (list components); `loadingStateView` on `CometChatNotificationFeed` |210| Custom header above the list | `headerView` |211| Custom message bubble | `templates` prop on `CometChatMessageList` (not a custom bubble component) |212| Click handler on item / message / search bar / back button | `onItemClick`, `onMessageClick`, `onBack`, `onSearchBarClicked` |213| Hide / disable a sub-feature | `disable*` boolean props (e.g. `disableTyping`, `disableReactions`) |214| Custom subtitle / status / timestamp | `subtitleView`, `statusView`, `timestampView` |215| Show / hide receipts | `hideReceipts` |216| Selection mode | `selectionMode` on list components |217218If you find a matching prop, **just add the prop and stop**. No new219components. No custom CSS. No new files. Surface to the user: *"The220`<X>` you already have supports this via the `<propName>` prop. Adding221that single prop."*222223If 2a turns up nothing, proceed to 2b.224225#### 2b. New-component check (do this only if 2a turned up nothing)226227**Common requests that look like "customization" but are actually228"use the existing component":**229230| User asks for | Use this built-in component |231|---|---|232| Threaded replies / "wire up threads" | `CometChatThreadHeader` + scope a `CometChatMessageList` and `CometChatMessageComposer` with `parentMessageId` |233| Group members panel / "list group members" | `CometChatGroupMembers` |234| Add members to a group | `CometChatAddMembers` |235| Transfer group ownership | `CometChatTransferOwnership` |236| Banned users management | `CometChatBannedMembers` |237| Block/unblock users panel | `CometChatBlockedUsers` |238| New chat / "start a new conversation" dialog | `CometChatNewChat` |239| Create new group dialog | `CometChatCreateGroup` |240| User / group details panel | `CometChatDetails` |241| Mentions popover in composer | `CometChatMentionsFormatter` (already wired into the composer) |242| Voice / video call buttons in header | `CometChatCallButtons` |243| Outgoing call screen | `CometChatOutgoingCall` |244| Incoming call notification | `CometChatIncomingCall` |245| Ongoing call UI | `CometChatOngoingCall` |246| Call logs list | `CometChatCallLogs` |247| Reactions on messages | Already built into `CometChatMessageList` — check if it's just disabled |248| Message bubble customization | Use the `templates` prop on `CometChatMessageList`, not a custom bubble component |249250> ⚠️ **Not every row above is a kit export.** `CometChatAddMembers`, `CometChatTransferOwnership`, `CometChatBannedMembers`, `CometChatBlockedUsers`, `CometChatNewChat`, `CometChatCreateGroup`, and `CometChatDetails` are **sample-app components, NOT `@cometchat/chat-uikit-react` v6 exports** — importing `<CometChatTransferOwnership/>` etc. is an unresolved-import build error. Build these by copying the sample-app implementation (§2d), do not import them from the package. The genuinely package-exported entries in this table are: `CometChatThreadHeader`, `CometChatGroupMembers`, `CometChatMentionsFormatter`, `CometChatCallButtons`, `CometChatOutgoingCall`, `CometChatIncomingCall`, `CometChatOngoingCall`, `CometChatCallLogs`. **Always grep the installed package's exports (next step) before emitting any of these.**251252**Search strategies, in this order:**2532541. **Query the docs MCP** with the user's intent in plain English.255 Examples:256 - `"thread reply UI react ui kit"` → finds `CometChatThreadHeader`257 - `"new chat dialog"` → finds `CometChatNewChat`258 - `"group transfer ownership"` → finds `CometChatTransferOwnership`259 - `"block user list"` → finds `CometChatBlockedUsers`2602. **Grep the user's installed package** for matching exports:261 ```bash262 grep -E "^export.*CometChat[A-Z][a-zA-Z]+" \263 node_modules/@cometchat/chat-uikit-react/dist/index.d.ts \264 2>/dev/null | head -50265 ```2663. **Browse the v6 components reference** at267 https://www.cometchat.com/docs/ui-kit/react/components-overview268269If you find a built-in component that matches, **use it as-is**.270Surface to the user: *"The kit already ships `CometChat<X>` for this.271I'll wire it up directly."*272273#### 2c. Stylesheet check (do this even when you DO need custom layout glue)274275Even when you have to write some CSS for layout glue (positioning a276panel, sizing a container, wiring up the height chain that277`.cometchat-message-list` requires), **never hand-pick colors, fonts,278borders, spacings, or radii from your head**. The kit ships a279canonical CSS variable system. Use it.280281**The rule:**282- ✅ **OK:** custom CSS for layout glue (positioning, sizing, flex283 containers, the height chain). Example: `.thread-wrapper { width:284 400px; height: 100vh; display: flex; flex-direction: column; }`285- ✅ **OK:** custom CSS that consumes kit variables. Example:286 `.thread-wrapper { border-left: 1px solid var(--cometchat-border-color-light); background: var(--cometchat-background-color-01); }`287- ❌ **NOT OK:** custom CSS for any header / button / icon / panel /288 badge / divider that the kit already provides as a component.289 Example: a hand-rolled `.thread-header` + `.thread-close` button when290 `CometChatThreadHeader` exists.291- ❌ **NOT OK:** hardcoded colors / fonts / borders / radii / spacings292 that don't reference the `--cometchat-*` variables. Example:293 `border: 1px solid #E8E8E8` instead of294 `border: 1px solid var(--cometchat-border-color-light)`.295296**Discovery commands for the variable system:**297```bash298# List every --cometchat-* variable the kit defines299grep -oE '\-\-cometchat-[a-z0-9-]+' \300 node_modules/@cometchat/chat-uikit-react/css-variables.css \301 2>/dev/null | sort -u | head -60302303# Or search for a specific token category304grep -E '\-\-cometchat-(border|background|text|primary|font)' \305 node_modules/@cometchat/chat-uikit-react/css-variables.css \306 2>/dev/null | head -40307```308309**Common variable categories** (query the docs MCP for the canonical310list — these change between SDK versions):311312| Category | Example variables |313|---|---|314| Brand colors | `--cometchat-primary-color`, `--cometchat-error-color`, `--cometchat-success-color` |315| Backgrounds | `--cometchat-background-color-01` (white), `--cometchat-background-color-02`, `--cometchat-background-color-03` (light grey) |316| Text | `--cometchat-text-color-primary`, `--cometchat-text-color-secondary`, `--cometchat-text-color-tertiary` |317| Borders | `--cometchat-border-color-light`, `--cometchat-border-color-default`, `--cometchat-border-color-dark` |318| Radii | `--cometchat-radius-1`, `--cometchat-radius-2`, `--cometchat-radius-3`, `--cometchat-radius-max` |319| Fonts | `--cometchat-font-heading1-bold`, `--cometchat-font-heading4-medium`, `--cometchat-font-body-regular`, `--cometchat-font-caption2-regular` |320| Spacing | `--cometchat-spacing-1` through `--cometchat-spacing-10` |321| Shadows | `--cometchat-shadow-1`, `--cometchat-shadow-2`, `--cometchat-shadow-3` |322323#### 2d. Sample app reference check (do this when 2a + 2b turned up nothing)324325If 2b didn't find a `CometChat<X>` component for the user's request,326**don't immediately conclude they need custom code**. The kit ships a327**reference sample app** at:328329> https://github.com/cometchat/cometchat-uikit-react/tree/v6/sample-app/src/components330331with implementations for common chat UX patterns that combine multiple332kit components but aren't shipped as single named exports. Examples333that look like "missing components" but are in the sample app:334335| User asks for | Sample app reference path |336|---|---|337| User / group details panel | `sample-app/src/components/CometChatDetails/CometChatUserDetails.tsx` (group details is inline in `CometChatHome.tsx`'s `SideComponentGroup`) |338| Threaded messages panel layout | `sample-app/src/components/CometChatDetails/CometChatThreadedMessages.tsx` |339| Top-level chat layout (left pane + main + side rail) | `sample-app/src/components/CometChatHome/CometChatHome.tsx` |340| Multi-tab chat (Chats / Calls / Users / Groups) | `sample-app/src/components/CometChatSelector/CometChatTabs.tsx` |341| New conversation dialog with user/group picker | Inline in `CometChatHome.tsx` as `CometChatNewChatView` (CSS: `sample-app/src/styles/CometChatNewChat/CometChatNewChatView.css`) |342| Search view (conversations + messages) | `sample-app/src/components/CometChatSearchView/` |343| Call log details / history / recordings | `sample-app/src/components/CometChatCallLog/` (5 sub-files: Details, History, Info, Participants, Recordings) |344| App state / active-chat React context | `sample-app/src/context/AppContext.jsx` + `appReducer.ts` |345| Group ownership transfer modal | `sample-app/src/components/CometChatTransferOwnership/` |346347These patterns include matching CSS at348`sample-app/src/styles/<ComponentName>/` using BEM-style class names349that are already wired to the kit's CSS variable system.350351**Discovery commands:**352353```bash354# List the sample app's components directory via the GitHub API355curl -s "https://api.github.com/repos/cometchat/cometchat-uikit-react/contents/sample-app/src/components?ref=v6" \356 | grep -oE '"name":\s*"[^"]+"' | head -30357358# Fetch a specific component file directly359curl -s "https://raw.githubusercontent.com/cometchat/cometchat-uikit-react/v6/sample-app/src/components/CometChatDetails/CometChatUserDetails.tsx"360361# Fetch its matching stylesheet362curl -s "https://raw.githubusercontent.com/cometchat/cometchat-uikit-react/v6/sample-app/src/styles/CometChatDetails/CometChatUserDetails.css"363```364365You can also use WebFetch on the URLs above. The docs MCP does NOT366index the sample app — you must fetch it from GitHub directly.367368**If you find a matching reference implementation:**3693701. Read BOTH the `.tsx` file AND its matching `.css` file (at371 `sample-app/src/styles/<ComponentName>/`)3722. Mirror the sample app's file/folder structure in the user's project,373 e.g. `src/cometchat/CometChatDetails/CometChatUserDetails.tsx` plus374 `src/cometchat/CometChatDetails/CometChatDetails.css`3753. Match the **exact BEM class names** from the sample376 (`.cometchat-user-details__header`,377 `.cometchat-user-details__content-avatar`, etc.) — they're already378 integrated with the kit's CSS variable system3794. Strip the sample app's local dependencies that the user's project380 doesn't have:381 - `useContext(AppContext)` → inline the values382 - `getLocalizedString(...)` → inline the English strings383 - `cometchat-resources/` SVG icons → use Unicode equivalents or384 strip them3855. Tell the user: *"The kit doesn't export this as a single component,386 but the official sample app has the reference implementation at387 `cometchat/cometchat-uikit-react/v6/sample-app/.../CometChat<X>`.388 I'm adapting it to your project."*389390#### 2e. After discovery — decide what to do391392In strict order, take the FIRST option that applies:3933941. **An existing component prop matches (2a):** add the prop. Done.395 No new files. Most chat features land here.3962. **A new component matches (2b) AND has its own styling:** use the397 component as-is. Zero custom CSS.3983. **A new component matches (2b) but you need layout glue:** use the399 component; write minimal layout-only CSS that consumes400 `--cometchat-*` variables (per 2c).4014. **Sample app has a reference implementation (2d):** adapt the402 sample app pattern, mirroring its file structure and BEM class403 names.4045. **None of the above:** then (and only then) proceed to Step 3 to405 classify the request as a true customization.406407### Step 3 — Classify the customization408409Read the user's request and place it into one of these buckets. The410right approach is different per bucket:411412| Bucket | Examples | Approach |413|---|---|---|414| **A. Custom view slot** | "add a custom header above the conversation list", "show a custom empty state", "render messages with my own bubble" | Use the corresponding `*View` prop (`headerView`, `emptyView`, `bubbleView`, etc.) — look up which prop the target component supports (list components use `emptyView`/`loadingView`/`errorView`; `CometChatNotificationFeed` uses the `*StateView` form) |415| **B. Filter / pagination** | "only show conversations with VIP users", "load 10 messages at a time", "show only joined groups" | Use the corresponding RequestBuilder (`ConversationsRequestBuilder.setTags`, `setLimit`, `setUserAndGroupTags`, etc.) — query the MCP for the builder methods |416| **C. Action / callback** | "do X when a user clicks a conversation", "intercept message send", "log every search" | Use the corresponding `on*` callback prop (`onItemClick`, `onSendButtonClick`, `onSearch`, etc.) — query the MCP for the callback signature |417| **D. Event subscription** | "show a toast when a new message arrives", "update my unread count when someone reads a message", "track typing indicators" | Subscribe to the corresponding `CometChat*Events` topic (`CometChatMessageEvents.ccMessageSent`, `ccMessageRead`, `CometChatUserEvents.ccUserOnline`, etc.) — query the MCP for the event topic |418| **E. Component-level CSS** | "make incoming bubbles green", "hide the conversation timestamps", "compact the message list spacing" | Add a CSS rule under `.cometchat <selector>` in the integration's global stylesheet — query the MCP for the right selector class. NEVER invent class names; the SDK's selectors are namespaced and prefix-protected. |419| **F. Component composition** | "wrap CometChatConversations with my own search bar", "render two CometChatGroups side by side", "embed CometChatMessageList inside my own card layout" | Standard React composition. The CometChat components are React components — use them like any other component. Query the MCP for which props are required vs optional. |420421> **Message templates / options / composer attachments → use the verified recipes in `cometchat-features` §Type 5**, not a hand-rolled `bubbleView`. Sending a custom message TYPE, overriding an existing type's bubble, adding a Forward-style message action, or adding a composer attachment all require the **append-not-replace** `CometChatUIKit.getDataSource()` merge (a bare `templates=`/`attachmentOptions=` array silently wipes the built-ins — ENG-35706). §Type 5 has the copy-ready, tsc-verified code.422423If the user's request doesn't fit any bucket, **ask them to clarify** —424don't guess. Customization is the place where ambiguous requests425produce wrong code most often.426427### Step 4 — Query the docs MCP for the canonical pattern (only if Step 2 turned up nothing)428429Once you've classified the request, query the docs MCP with a specific430search:431432| Bucket | MCP query example |433|---|---|434| A. Custom view slot | "headerView prop CometChatConversations" |435| B. Filter / pagination | "ConversationsRequestBuilder methods setTags" |436| C. Action / callback | "CometChatMessageList onMessageClick callback signature" |437| D. Event subscription | "CometChatMessageEvents ccMessageSent subscribe" |438| E. Component-level CSS | "CSS selector cometchat-message-bubble-incoming" |439| F. Component composition | "CometChatConversations props required" |440441The MCP returns canonical, current docs. Read them BEFORE writing any442code. If multiple results come back, prefer the React UI Kit v6 result443over older versions.444445### Step 5 — Identify the file to modify446447Use the framework + experience you noted in Step 1 to find the right448file. The integration's primary client file is conventional per449framework:450451| Framework | Primary client file |452|---|---|453| reactjs (Vite) | `src/App.tsx` (renders the conversation list / messages) + `src/cometchat/CometChatSelector.tsx` (the selector) |454| nextjs (App Router) | `src/app/cometchat/CometChatNoSSR.tsx` (renders the chat) + `src/app/cometchat/CometChatSelector.tsx` (the selector) |455| nextjs (Pages Router) | `src/cometchat/CometChatNoSSR.tsx` + `src/cometchat/CometChatSelector.tsx` |456| react-router (v6 + v7) | `app/cometchat/CometChatNoSSR.tsx` + `app/cometchat/CometChatSelector.tsx` |457| astro | `src/cometchat/ChatApp.tsx` (the React island) + `src/cometchat/CometChatSelector.tsx` |458459For CSS overrides (bucket E), the global stylesheet is:460- reactjs → `src/index.css`461- nextjs (App Router) → `src/app/globals.css`462- nextjs (Pages Router) → `src/styles/globals.css`463- react-router → `app/app.css`464- astro → inside `src/cometchat/ChatApp.tsx` (NOT a global stylesheet)465466These are also in `state.json` under `files_owned` if you need to verify.467468### Step 6 — Write the customization469470Generate the code based on the docs MCP response from Step 4. Show the471user:4724731. **What you're going to change** (which file, which lines, the new474 code)4752. **Why** (which prop/builder/event the docs say to use)4763. **A preview of the diff** (just the changed region, not the whole477 file)478479**Wait for the user to confirm** before writing. Customization edits480the integration's owned files — drift detection will show this on the481next `cometchat info`. The user should know.482483If the user confirms, write the change. If they don't, surface what484they'd want to change and stop.485486### Step 7 — Verify487488```bash489npx @cometchat/skills-cli verify --json490```491492The 5 AST checks still apply to customized files. If anything fails,493surface verbatim and offer to revert.494495```bash496npx @cometchat/skills-cli info --json497```498499The customized file will now show as drifted (its checksum no longer500matches the original template). This is expected — it's the501**explicit** drift the user just asked for. Not a bug.502503### Step 8 — Tell the user what to do next504505The dev server picks up React changes via HMR. Tell the user:5061. Save the file (if their editor doesn't auto-save)5072. Refresh the browser tab5083. Test the customization509510Then offer to do another customization OR to return to the framework511skill's Phase B menu.512513## Hard rules514515- **Always do the FOUR-tier discovery before adding any new component516 or hand-rolled UI.** The kit follows a "props over components"517 philosophy and ships FOUR things, not one:518 (0) **props** on already-mounted components for most features519 (search bar, filters, custom views, click handlers, disable520 flags) — check this FIRST,521 (1) 60+ named React components in `@cometchat/chat-uikit-react`,522 (2) a 200+ CSS variable system in `css-variables.css`,523 (3) a reference sample app at524 `github.com/cometchat/cometchat-uikit-react/tree/v6/sample-app/src/components`525 with implementations for common chat UX patterns that combine526 multiple kit components but aren't shipped as single named527 exports (user/group details panels, thread layouts, top-level528 home layout, notifications, new chat dialog, etc.).529 The docs MCP does NOT index the sample app — fetch it from GitHub530 directly. Adding a new component when an existing one's prop would531 do, or hand-rolling something the kit, the variable system, or the532 sample app already provides, means missing the kit's theming, i18n,533 accessibility, and every future SDK update. Step 2 (subsections 2a534 + 2b + 2c + 2d) is mandatory — do NOT skip it. **2a535 (existing-component prop check) goes FIRST** because most features536 are props on already-mounted components, not new components.537- **Custom CSS is allowed ONLY for layout glue** (positioning,538 sizing, flex/grid containers, the height chain). Even there, never539 hardcode colors / fonts / borders / radii / spacings — always540 reference `--cometchat-*` variables. Hand-rolled headers, buttons,541 icons, panels, badges, dividers, etc. are NEVER OK if the kit542 already provides them.543- **Always query the docs MCP first** for any prop, builder, event, or544 CSS selector. Never invent SDK API from memory.545- **Verify Phase A is done** before customizing. This skill modifies546 existing integration files; it does not create new ones.547- **Show the user the change before writing**. Customization is548 user-side intent — they need visibility.549- **Drift detection is expected after customization**, not a bug.550 The user's customizations live in `state.files_owned` and will551 show up in `cometchat info` as modified. That's correct.552- **Prefer composition over CSS overrides** when both are options —553 composition is stable across SDK versions; CSS selectors are not.554- **Never invent CSS class names** — look them up in the docs. The SDK's555 class prefix is `.cometchat-` but the leaf names (`-message-bubble-incoming`,556 `-conversations-header`, etc.) MUST come from the docs.557- **Look up the docs via the best available path** (see §2's lookup558 contract): docs MCP if your agent has it → else fetch/web-search the559 public docs at cometchat.com/docs. Never STOP just because the MCP560 isn't installed — fall through to the public docs.561- **Always use `npx @cometchat/skills-cli`** for any CLI commands.562563## What this skill does NOT do564565- It does not write **template** files (that's `cometchat init`)566- It does not **enable packaged features** (that's `cometchat-features`567 + `cometchat apply-feature`)568- It does not **change theme tokens** (that's `cometchat-theming` —569 CSS-variable overrides, no CLI)570- It does not **fix broken integrations** (that's571 `cometchat-troubleshooting` + `cometchat doctor`)572- It does not **add new components from scratch** — it customizes573 components that the integration already uses574575For anything in the "does not" list, route the user to the right576skill/command instead of attempting it here.577578## Sound (in-app message + call sounds)579580Sound is a customization sub-dimension. The UI Kit plays incoming/outgoing message + call sounds via `CometChatSoundManager` — mute it, swap custom audio, or play a specific sound. The full API + recipe lives in **`cometchat-theming`** (Sound section). Verify the access path against the installed kit before relying on it.