@cometchat/skills 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,642 @@
1
+ ---
2
+ name: cometchat-core
3
+ description: "Shared rules for CometChat React UI Kit v6. Always loaded alongside framework + placement skills. Read this first."
4
+ license: "MIT"
5
+ compatibility: "Node.js >=18; React >=18; @cometchat/chat-uikit-react ^6; @cometchat/chat-sdk-javascript ^4"
6
+ allowed-tools: "executeBash, readFile, fileSearch, listDirectory"
7
+ metadata:
8
+ author: "CometChat"
9
+ version: "3.0.0"
10
+ tags: "chat cometchat react core rules initialization patterns"
11
+ ---
12
+
13
+ ## Purpose
14
+
15
+ This is the foundational skill for every CometChat React UI Kit v6 integration. It teaches Claude HOW CometChat works -- initialization, login, CSS, environment variables, SSR safety, and the provider pattern -- so Claude can write project-appropriate code instead of relying on templates.
16
+
17
+ **Read this skill first, before any framework or placement skill.**
18
+
19
+ ---
20
+
21
+ ## 1. Initialization
22
+
23
+ CometChat must be initialized exactly once before any UI component renders. Initialization is asynchronous and must complete fully before mounting any `CometChat*` component.
24
+
25
+ ### The UIKitSettingsBuilder
26
+
27
+ ```typescript
28
+ import { CometChatUIKit, UIKitSettingsBuilder } from "@cometchat/chat-uikit-react";
29
+
30
+ const settings = new UIKitSettingsBuilder()
31
+ .setAppId(APP_ID) // Required. String from the CometChat dashboard.
32
+ .setRegion(REGION) // Required. "us", "eu", "in", etc.
33
+ .setAuthKey(AUTH_KEY) // Required for dev mode. Omit in production (use auth tokens).
34
+ .subscribePresenceForAllUsers() // Optional but recommended -- enables online/offline indicators.
35
+ .build();
36
+ ```
37
+
38
+ ### Init must happen once
39
+
40
+ Use a module-level flag to prevent double-init. This is critical because React StrictMode in development calls effects twice:
41
+
42
+ ```typescript
43
+ let initialized = false;
44
+
45
+ async function initCometChat(): Promise<void> {
46
+ if (initialized) return;
47
+ initialized = true;
48
+
49
+ const settings = new UIKitSettingsBuilder()
50
+ .setAppId(APP_ID)
51
+ .setRegion(REGION)
52
+ .setAuthKey(AUTH_KEY)
53
+ .subscribePresenceForAllUsers()
54
+ .build();
55
+
56
+ await CometChatUIKit.init(settings);
57
+ }
58
+ ```
59
+
60
+ ### Init must be in useEffect (React components) or before mount (entry files)
61
+
62
+ **In a useEffect (Next.js, Astro, React Router SSR):**
63
+
64
+ ```typescript
65
+ useEffect(() => {
66
+ initCometChat()
67
+ .then(() => loginUser())
68
+ .then(() => setReady(true))
69
+ .catch((e) => setError(String(e)));
70
+ }, []);
71
+ ```
72
+
73
+ **At the entry point (Vite/CRA -- no SSR):**
74
+
75
+ ```typescript
76
+ // main.tsx -- runs once, before React mounts
77
+ CometChatUIKit.init(settings)
78
+ ?.then(() => CometChatUIKit.login("cometchat-uid-1"))
79
+ .then(() => mount())
80
+ .catch((e) => mountError(String(e)));
81
+ ```
82
+
83
+ The init-at-entry pattern works for Vite/CRA because `main.tsx` only runs in the browser. For frameworks with SSR (Next.js, Astro, React Router v7 SSR), you MUST use the useEffect pattern because the module runs on the server first.
84
+
85
+ ---
86
+
87
+ ## 2. Login
88
+
89
+ ### Development mode
90
+
91
+ Use `CometChatUIKit.login(uid)` with a test UID. Every new CometChat app comes with five pre-created test users: `cometchat-uid-1` through `cometchat-uid-5`.
92
+
93
+ ```typescript
94
+ const user = await CometChatUIKit.getLoggedinUser();
95
+ if (!user) {
96
+ await CometChatUIKit.login("cometchat-uid-1");
97
+ }
98
+ ```
99
+
100
+ ### ⚠️ `login()` is safe to call sequentially, NOT concurrently
101
+
102
+ A subtle but important distinction:
103
+
104
+ - **Sequential** (first `login()` completes, then second is called): the SDK's second call returns immediately with the already-logged-in user. Safe.
105
+ - **Concurrent** (a second `login()` fires while the first is still in-flight): the SDK throws `"Please wait until the previous login request ends."` The user sees a red error on the page, has to refresh, and only then does it work (because the first session is now cached).
106
+
107
+ This is exactly the case that React 18 StrictMode triggers in development: effects run mount → unmount → mount, so a `useEffect` that calls `login()` fires twice with no time for the first call to finish. Production builds don't double-mount, but any code path that can call `login()` from two places simultaneously hits the same error.
108
+
109
+ **Guard concurrent login with a module-level in-flight promise:**
110
+
111
+ ```typescript
112
+ let loginInFlight: Promise<unknown> | null = null;
113
+
114
+ async function ensureLoggedIn(
115
+ uid: string,
116
+ authToken?: string,
117
+ ): Promise<void> {
118
+ const existing = await CometChatUIKit.getLoggedinUser();
119
+ if (existing) return; // sequential case — already logged in
120
+ if (loginInFlight) { // concurrent case — reuse pending promise
121
+ await loginInFlight;
122
+ return;
123
+ }
124
+ loginInFlight = authToken
125
+ ? CometChatUIKit.loginWithAuthToken(authToken)
126
+ : CometChatUIKit.login(uid);
127
+ try {
128
+ await loginInFlight;
129
+ } finally {
130
+ loginInFlight = null;
131
+ }
132
+ }
133
+ ```
134
+
135
+ Call `ensureLoggedIn()` from the provider / effect instead of `CometChatUIKit.login()` directly. Both StrictMode mounts resolve against the same promise, so only one login request actually hits the server.
136
+
137
+ **Why not just a boolean flag?** A boolean would require extra wait-loop code to handle "login started but not finished yet." A cached promise handles that automatically — `await` on the same promise is free for all callers.
138
+
139
+ ### Getting the current logged-in UID in app code
140
+
141
+ When your integration code needs the current user's UID (for example, to decide which conversation to target, or to filter by sender), **always fetch it from the SDK — never hardcode a UID like `"cometchat-uid-1"`**.
142
+
143
+ Two getters, for different contexts:
144
+
145
+ ```typescript
146
+ // Async — preferred for app logic, guaranteed correct after init completes
147
+ const me = await CometChatUIKit.getLoggedinUser();
148
+ const myUid = me?.getUid();
149
+
150
+ // Sync — use inside render paths where you already know init is done
151
+ import { CometChatUIKitLoginListener } from "@cometchat/chat-uikit-react";
152
+ const me = CometChatUIKitLoginListener.getLoggedInUser(); // note capital `I` in `InUser`
153
+ const myUid = me?.getUid();
154
+ ```
155
+
156
+ Hardcoding `"cometchat-uid-1"` only works in the dev mode login call (`CometChatUIKit.login("cometchat-uid-1")`) because you're *choosing* who to log in as. Once logged in, the getters are the source of truth — useful when the logged-in user comes from production auth (a real user ID, not a test UID), or when the user logs out and logs in as someone else.
157
+
158
+ ### Production mode
159
+
160
+ Use `CometChatUIKit.loginWithAuthToken(token)` with a token obtained from your backend. The backend generates the token using the CometChat REST API with your `AUTH_TOKEN` (not the client-side `AUTH_KEY`).
161
+
162
+ ```typescript
163
+ // Fetch token from YOUR backend, which calls CometChat's REST API
164
+ const response = await fetch("/api/cometchat-token", {
165
+ method: "POST",
166
+ headers: { "Content-Type": "application/json" },
167
+ body: JSON.stringify({ uid: currentUser.id }),
168
+ });
169
+ const { token } = await response.json();
170
+
171
+ await CometChatUIKit.loginWithAuthToken(token);
172
+ ```
173
+
174
+ For the full production auth setup, use `npx @cometchat/skills-cli production-auth`. Never hardcode auth keys in source code that ships to production.
175
+
176
+ ### Logout
177
+
178
+ ```typescript
179
+ await CometChatUIKit.logout();
180
+ ```
181
+
182
+ Call this when the user signs out of your application. This clears CometChat's local session.
183
+
184
+ ---
185
+
186
+ ## 3. CSS
187
+
188
+ ### Import once at the app root
189
+
190
+ ```typescript
191
+ import "@cometchat/chat-uikit-react/css-variables.css";
192
+ ```
193
+
194
+ This import MUST appear exactly once, at the highest level of your application:
195
+
196
+ | Framework | Where to import |
197
+ |---|---|
198
+ | React (Vite) | `src/main.tsx` or `src/index.css` via `@import` |
199
+ | Next.js (App Router) | `app/globals.css` via `@import` or `app/layout.tsx` |
200
+ | Next.js (Pages Router) | `pages/_app.tsx` or `styles/globals.css` |
201
+ | Astro | Global layout file or `src/styles/global.css` |
202
+ | React Router | Root route module or `app/root.tsx` |
203
+
204
+ ### Theming with CSS variables
205
+
206
+ All CometChat components respect `--cometchat-*` CSS variables. Override them on a parent element or `:root`:
207
+
208
+ ```css
209
+ :root {
210
+ --cometchat-primary-color: #6851d6;
211
+ --cometchat-background-color-01: #ffffff;
212
+ --cometchat-text-color-primary: #141414;
213
+ --cometchat-font-family: "Inter", sans-serif;
214
+ --cometchat-border-radius-lg: 12px;
215
+ }
216
+ ```
217
+
218
+ ### Never target internal class names
219
+
220
+ CometChat's internal class names (like `.cometchat-message-bubble__wrapper`) are not part of the public API and may change between versions. Always use CSS variables for customization. The only exception is when explicitly copying patterns from the v6 sample app that use documented BEM class names.
221
+
222
+ ---
223
+
224
+ ## 4. Environment variables
225
+
226
+ Each framework has its own convention for exposing env vars to client-side code. CometChat needs three variables: `APP_ID`, `REGION`, and `AUTH_KEY`.
227
+
228
+ ### Per-framework naming
229
+
230
+ | Framework | Prefix | Example |
231
+ |---|---|---|
232
+ | React (Vite) | `VITE_` | `import.meta.env.VITE_COMETCHAT_APP_ID` |
233
+ | Next.js | `NEXT_PUBLIC_` | `process.env.NEXT_PUBLIC_COMETCHAT_APP_ID` |
234
+ | Astro | `PUBLIC_` | `import.meta.env.PUBLIC_COMETCHAT_APP_ID` |
235
+ | React Router (Vite) | `VITE_` | `import.meta.env.VITE_COMETCHAT_APP_ID` |
236
+ | CRA | `REACT_APP_` | `process.env.REACT_APP_COMETCHAT_APP_ID` |
237
+
238
+ ### The three variables
239
+
240
+ | Variable suffix | Required | Description |
241
+ |---|---|---|
242
+ | `COMETCHAT_APP_ID` | Yes | Your app ID from the CometChat dashboard |
243
+ | `COMETCHAT_REGION` | Yes | Region code: `"us"`, `"eu"`, `"in"`, etc. |
244
+ | `COMETCHAT_AUTH_KEY` | Dev only | Client-side auth key. Replace with auth tokens for production. |
245
+
246
+ ### .env file placement
247
+
248
+ | Framework | File | Gitignored by default |
249
+ |---|---|---|
250
+ | Vite / React Router | `.env` | No -- add to `.gitignore` |
251
+ | Next.js | `.env.local` | Yes |
252
+ | Astro | `.env` | No -- add to `.gitignore` |
253
+ | CRA | `.env` | No -- add to `.gitignore` |
254
+
255
+ ---
256
+
257
+ ## 5. SSR safety
258
+
259
+ All CometChat UI Kit components are browser-only. They access `window`, `document`, and browser APIs during import. Rendering them on the server will crash.
260
+
261
+ ### Framework-specific SSR prevention
262
+
263
+ **Next.js (App Router):**
264
+
265
+ Mark the file containing CometChat components with `"use client"` at the top. Use `next/dynamic` with `ssr: false` if the component is imported from a server component:
266
+
267
+ ```typescript
268
+ "use client";
269
+ // This entire file only runs in the browser
270
+
271
+ import { CometChatConversations } from "@cometchat/chat-uikit-react";
272
+ ```
273
+
274
+ Or from a server component:
275
+
276
+ ```typescript
277
+ import dynamic from "next/dynamic";
278
+
279
+ const ChatView = dynamic(() => import("./ChatView"), { ssr: false });
280
+ ```
281
+
282
+ **Next.js (Pages Router):**
283
+
284
+ Use `next/dynamic` with `ssr: false`:
285
+
286
+ ```typescript
287
+ import dynamic from "next/dynamic";
288
+
289
+ const CometChatNoSSR = dynamic(() => import("../components/CometChatNoSSR"), {
290
+ ssr: false,
291
+ });
292
+ ```
293
+
294
+ **Astro:**
295
+
296
+ Use the `client:only="react"` directive. This prevents the component from rendering during Astro's static build:
297
+
298
+ ```astro
299
+ ---
300
+ import ChatPanel from "../components/ChatPanel";
301
+ ---
302
+ <ChatPanel client:only="react" />
303
+ ```
304
+
305
+ **React Router v7 (SSR mode):**
306
+
307
+ Use `React.lazy()` with `Suspense` in a `clientLoader` or `useEffect` guard:
308
+
309
+ ```typescript
310
+ import { lazy, Suspense } from "react";
311
+
312
+ const ChatView = lazy(() => import("./ChatView"));
313
+
314
+ export default function ChatRoute() {
315
+ const [mounted, setMounted] = useState(false);
316
+ useEffect(() => setMounted(true), []);
317
+
318
+ if (!mounted) return null;
319
+ return (
320
+ <Suspense fallback={<div>Loading chat...</div>}>
321
+ <ChatView />
322
+ </Suspense>
323
+ );
324
+ }
325
+ ```
326
+
327
+ **React (Vite / CRA):**
328
+
329
+ No SSR concerns. These are client-only by nature. Import and use directly.
330
+
331
+ ---
332
+
333
+ ## 6. Provider pattern
334
+
335
+ Instead of inlining init/login logic in every component, create a reusable `CometChatProvider` that handles initialization, login, and ready-state gating. Wrap your chat UI with it.
336
+
337
+ ```typescript
338
+ // CometChatProvider.tsx
339
+ "use client"; // Required for Next.js App Router; harmless in other frameworks
340
+
341
+ import React, { useEffect, useState, createContext, useContext } from "react";
342
+ import { CometChatUIKit, UIKitSettingsBuilder } from "@cometchat/chat-uikit-react";
343
+
344
+ interface CometChatContextValue {
345
+ isReady: boolean;
346
+ error: string | null;
347
+ }
348
+
349
+ const CometChatContext = createContext<CometChatContextValue>({
350
+ isReady: false,
351
+ error: null,
352
+ });
353
+
354
+ export const useCometChat = () => useContext(CometChatContext);
355
+
356
+ // Module-level state: shared across all mounts so React 18 StrictMode's
357
+ // double-invocation of effects doesn't fire init or login twice.
358
+ let initialized = false;
359
+ let loginInFlight: Promise<unknown> | null = null;
360
+
361
+ async function ensureLoggedIn(
362
+ uid: string,
363
+ authToken?: string,
364
+ ): Promise<void> {
365
+ const existing = await CometChatUIKit.getLoggedinUser();
366
+ if (existing) return;
367
+ if (loginInFlight) {
368
+ // A prior StrictMode mount (or another effect) already started login —
369
+ // reuse its promise instead of calling login() a second time, which
370
+ // throws "Please wait until the previous login request ends."
371
+ await loginInFlight;
372
+ return;
373
+ }
374
+ loginInFlight = authToken
375
+ ? CometChatUIKit.loginWithAuthToken(authToken)
376
+ : CometChatUIKit.login(uid);
377
+ try {
378
+ await loginInFlight;
379
+ } finally {
380
+ loginInFlight = null;
381
+ }
382
+ }
383
+
384
+ interface CometChatProviderProps {
385
+ appId: string;
386
+ region: string;
387
+ authKey?: string;
388
+ authToken?: string;
389
+ uid?: string;
390
+ children: React.ReactNode;
391
+ }
392
+
393
+ export function CometChatProvider({
394
+ appId,
395
+ region,
396
+ authKey,
397
+ authToken,
398
+ uid = "cometchat-uid-1",
399
+ children,
400
+ }: CometChatProviderProps) {
401
+ const [isReady, setIsReady] = useState(false);
402
+ const [error, setError] = useState<string | null>(null);
403
+
404
+ useEffect(() => {
405
+ async function setup() {
406
+ try {
407
+ if (!initialized) {
408
+ initialized = true;
409
+ const builder = new UIKitSettingsBuilder()
410
+ .setAppId(appId)
411
+ .setRegion(region)
412
+ .subscribePresenceForAllUsers();
413
+
414
+ if (authKey) {
415
+ builder.setAuthKey(authKey);
416
+ }
417
+
418
+ const settings = builder.build();
419
+ await CometChatUIKit.init(settings);
420
+ }
421
+
422
+ await ensureLoggedIn(uid, authToken);
423
+
424
+ setIsReady(true);
425
+ } catch (e) {
426
+ setError(String(e));
427
+ }
428
+ }
429
+
430
+ setup();
431
+ }, [appId, region, authKey, authToken, uid]);
432
+
433
+ if (error) {
434
+ return (
435
+ <div style={{ color: "red", padding: 16, fontFamily: "monospace" }}>
436
+ CometChat Error: {error}
437
+ </div>
438
+ );
439
+ }
440
+
441
+ if (!isReady) {
442
+ return null; // Or a loading spinner
443
+ }
444
+
445
+ return (
446
+ <CometChatContext.Provider value={{ isReady, error }}>
447
+ {children}
448
+ </CometChatContext.Provider>
449
+ );
450
+ }
451
+ ```
452
+
453
+ ### Usage
454
+
455
+ ```typescript
456
+ // In your app layout or route wrapper:
457
+ <CometChatProvider
458
+ appId={import.meta.env.VITE_COMETCHAT_APP_ID}
459
+ region={import.meta.env.VITE_COMETCHAT_REGION}
460
+ authKey={import.meta.env.VITE_COMETCHAT_AUTH_KEY}
461
+ >
462
+ <ChatPage />
463
+ </CometChatProvider>
464
+ ```
465
+
466
+ The provider pattern keeps init/login logic in one place. Chat components inside `<CometChatProvider>` are guaranteed to render only after init and login succeed.
467
+
468
+ ---
469
+
470
+ ## 7. RTL, i18n, and accessibility
471
+
472
+ These three concerns share one property: the UI Kit handles them out of the box, but a careless customization can break them. Read this before writing custom views, composer actions, or header replacements.
473
+
474
+ ### RTL (right-to-left)
475
+
476
+ The UI Kit reads `dir="rtl"` from the document root. If the project already sets `<html dir="rtl">` (or toggles it dynamically for Arabic/Hebrew locales), **CometChat components flip automatically** — message bubbles mirror, avatars swap sides, icons rotate where appropriate. No CometChat-specific config needed.
477
+
478
+ **To test:** add `<html dir="rtl">` to `index.html` (or set it via JS in Next.js App Router: `<html dir="rtl">` in `app/layout.tsx`). Reload — the conversation list avatar + text should render on the right, message bubbles mirror, the composer input aligns right.
479
+
480
+ **When customizing:** if you replace a default view (e.g. a custom message bubble), test it in both LTR and RTL. The UI Kit's components use logical properties (`margin-inline-start`, `padding-inline-end`) — your custom components should too, or they'll break RTL.
481
+
482
+ ### i18n (translations)
483
+
484
+ The UI Kit has a built-in `CometChatLocalize` utility that covers ~40 languages out of the box. Initialize it once, alongside `CometChatUIKit.init()`:
485
+
486
+ ```typescript
487
+ import { CometChatLocalize } from "@cometchat/chat-uikit-react";
488
+
489
+ CometChatLocalize.init({
490
+ language: "es", // or "fr", "de", "ar", "hi", etc.
491
+ });
492
+ ```
493
+
494
+ For a dynamic language switcher, call `CometChatLocalize.setLocale(newLang)` when the user picks a language. The UI Kit re-renders with the new strings.
495
+
496
+ **To override a string:** the `resources` option accepts custom translations merged over the defaults. Useful for brand-specific terms:
497
+
498
+ ```typescript
499
+ CometChatLocalize.init({
500
+ language: "en",
501
+ resources: {
502
+ en: {
503
+ "type a message": "Write your message…",
504
+ "start a conversation": "Say hi 👋",
505
+ },
506
+ },
507
+ });
508
+ ```
509
+
510
+ **Full translation key list** lives in `node_modules/@cometchat/chat-uikit-react/dist/resources/` or the docs MCP. Don't invent keys — unknown keys fall through to the default.
511
+
512
+ ### Accessibility
513
+
514
+ Default components ship with:
515
+ - `aria-label` on icon-only buttons (send, attach, call, etc.)
516
+ - `role="listbox"` + `role="option"` on conversation / user / group lists
517
+ - Keyboard navigation: `Tab` to focus, `Enter` to activate, `Esc` to close modals
518
+ - Focus management: opening a thread view moves focus to the thread header; closing returns focus to the trigger
519
+
520
+ **Rules when customizing:**
521
+
522
+ 1. **Replacing an icon-only button?** Add `aria-label="<verb>"` (e.g. `aria-label="Send message"`).
523
+ 2. **Replacing a list item?** Keep `role="option"` + `aria-selected` on the wrapping element.
524
+ 3. **Replacing the composer?** Preserve the `<textarea>` with an accessible `<label>` (visible or `aria-label`), and keep `Enter`/`Shift+Enter` behavior.
525
+ 4. **Replacing a modal?** Trap focus inside the modal while open, restore focus to the trigger on close, and add `role="dialog"` + `aria-modal="true"` + a labelled heading.
526
+ 5. **Color contrast:** when theming with custom colors, verify text contrast ≥ 4.5:1 against background. A low-saturation primary color on a white background breaks AA contrast.
527
+
528
+ For deep customization (e.g. a fully custom message bubble), the a11y responsibility shifts to the custom component — the UI Kit only guarantees it for its own defaults. Test with a screen reader (VoiceOver on macOS, NVDA on Windows) and keyboard-only navigation before shipping.
529
+
530
+ ---
531
+
532
+ ## 8. Anti-patterns
533
+
534
+ These are specific things NOT to do. Each one causes real bugs that are hard to debug.
535
+
536
+ 1. **Do NOT call `CometChatUIKit.init()` during render.** Init is async and has side effects. Calling it during render causes infinite re-render loops. Always call in `useEffect` or before `createRoot`.
537
+
538
+ 2. **Do NOT import `css-variables.css` in multiple files.** Duplicate imports cause CSS specificity conflicts and doubled variable declarations. Import it exactly once at the app root.
539
+
540
+ 3. **Do NOT render CometChat components before init completes.** Components assume the SDK is initialized. Rendering before init finishes causes "CometChat is not initialized" runtime errors. Use the provider pattern or a ready-state gate.
541
+
542
+ 4. **Do NOT hardcode `AUTH_KEY` in source files.** The auth key is a secret. Use environment variables during development. Use auth tokens in production.
543
+
544
+ 5. **Guard concurrent `login()` calls with a module-level in-flight promise.** `login()` is only safe to call sequentially. Two `login()` calls overlapping (e.g. React 18 StrictMode's double effect) throw *"Please wait until the previous login request ends."* Cache the first login's promise at module scope and `await` that from subsequent callers. See the `ensureLoggedIn` helper in section 2 and section 6's provider pattern.
545
+
546
+ 6. **Do NOT render CometChat components in a server-side context.** All components require browser APIs. In Next.js, always use `"use client"`. In Astro, always use `client:only="react"`.
547
+
548
+ 7. **Do NOT target CometChat's internal CSS class names for styling.** These are not part of the public API. Use `--cometchat-*` CSS variables instead. Internal classes change between minor versions.
549
+
550
+ 8. **Do NOT create CometChat components without a container that has explicit dimensions.** CometChat components fill 100% of their container. If the container has no height, the components collapse to zero height. Always set `height`, `min-height`, or use flexbox/grid to give the container dimensions.
551
+
552
+ 9. **Do NOT re-initialize CometChat when navigating between routes.** Init should happen once at the app level (in the provider or entry file), not per-route. Re-initializing causes flickering and dropped WebSocket connections.
553
+
554
+ 10. **Do NOT invent component names.** CometChat exports specific components with specific names. Check the `cometchat-components` skill before writing any `<CometChat*>` JSX. Using a wrong name (e.g., `<CometChatChat>`, `<CometChatMessenger>`) causes a build error.
555
+
556
+ 11. **Do NOT wrap CometChat components in a `transform`ed container.** Per the CSS spec, any non-`none` `transform` on an element creates a new containing block for `position: fixed` descendants. CometChat UI Kit renders several overlays as `position: fixed` (message options menu, emoji picker, file preview, reactions popover, thread panel) and expects them to anchor to the viewport. Wrapping the chat in a container that uses `transform: translateX(...)` — a common pattern for slide-in drawers / sidebars — reparents those overlays to the drawer, causing them to appear clipped, offset, or drift mid-animation.
557
+
558
+ **This includes Tailwind's `translate-x-*` utilities — `translate-x-full`, `-translate-x-full`, `translate-x-0`, `translate-x-[420px]`, etc. all compile to `transform: translateX(...)` and trigger the same bug.** Same for `-translate-y-*`, `translate-*`, `scale-*`, `rotate-*`, `skew-*`, `transform-*`, and any `transition-transform` utility applied to a container wrapping CometChat components. If you see yourself reaching for any Tailwind class in the `transform:` family on a drawer/sidebar/modal that contains chat UI, stop.
559
+
560
+ **Animate the `right` / `left` offset instead**, or use `margin-right: isOpen ? 0 : -<width>`. In Tailwind: toggle between `right-0` and a negative `right-[-420px]` with `transition-[right]` instead of `transition-transform`.
561
+
562
+ Same rule applies to `filter`, `perspective`, `backdrop-filter`, and `will-change: transform` — any of those also trigger the containing-block takeover. See `cometchat-placement`'s drawer and widget patterns for the correct right-offset animation.
563
+
564
+ ---
565
+
566
+ ## 9. Docs MCP (recommended, not required)
567
+
568
+ The CometChat docs MCP provides runtime access to the latest documentation, including prop types, callback signatures, request builder methods, SDK events, CSS variable names, and error decoders.
569
+
570
+ ### Installation
571
+
572
+ ```bash
573
+ claude mcp add --transport http cometchat-docs https://www.cometchat.com/docs/mcp
574
+ ```
575
+
576
+ For other clients, see: https://www.cometchat.com/docs/mcp-server
577
+
578
+ ### When to use
579
+
580
+ - Looking up a prop's exact type or default value
581
+ - Finding callback signatures (e.g., what `onItemClick` passes)
582
+ - Checking request builder methods (e.g., `ConversationsRequestBuilder.setLimit`)
583
+ - Understanding SDK events (e.g., `CometChatMessageEvents.ccMessageSent`)
584
+ - Verifying CSS variable names before writing overrides
585
+ - Decoding error messages (e.g., "INVALID_AUTH_KEY")
586
+
587
+ ### When NOT to use
588
+
589
+ - For component names and basic props -- use the `cometchat-components` skill instead (it works offline)
590
+ - For init/login/CSS patterns -- they are in this skill
591
+ - For placement patterns -- they are in the `cometchat-placement` skill
592
+ - For anything the CLI handles -- the CLI templates are the source of truth for those paths
593
+
594
+ ### Fallback when not installed
595
+
596
+ If the docs MCP is not installed and you need information beyond what the component and core skills contain, check the installed TypeScript definitions:
597
+
598
+ ```bash
599
+ grep -A 80 "interface CometChat<ComponentName>Props" \
600
+ node_modules/@cometchat/chat-uikit-react/dist/index.d.ts \
601
+ 2>/dev/null | head -80
602
+ ```
603
+
604
+ This is faster and more accurate than guessing from training data. Never invent SDK signatures from memory.
605
+
606
+ ---
607
+
608
+ ## 10. Package dependencies
609
+
610
+ Every CometChat React integration requires these two packages:
611
+
612
+ ```json
613
+ {
614
+ "@cometchat/chat-uikit-react": "^6",
615
+ "@cometchat/chat-sdk-javascript": "^4"
616
+ }
617
+ ```
618
+
619
+ The UI Kit (`@cometchat/chat-uikit-react`) provides all the React components. The SDK (`@cometchat/chat-sdk-javascript`) provides the `CometChat` namespace with types (`CometChat.User`, `CometChat.Group`, `CometChat.Conversation`, `CometChat.BaseMessage`) and methods.
620
+
621
+ Install with your project's package manager:
622
+
623
+ ```bash
624
+ npm install @cometchat/chat-uikit-react @cometchat/chat-sdk-javascript
625
+ ```
626
+
627
+ ### SDK types you will use
628
+
629
+ ```typescript
630
+ import { CometChat } from "@cometchat/chat-sdk-javascript";
631
+
632
+ // Common types:
633
+ CometChat.User // A chat user
634
+ CometChat.Group // A chat group
635
+ CometChat.Conversation // A conversation (wraps User or Group)
636
+ CometChat.BaseMessage // A message (text, media, custom, etc.)
637
+ CometChat.TextMessage // A text message specifically
638
+
639
+ // Common static methods:
640
+ CometChat.getUser(uid: string): Promise<CometChat.User>
641
+ CometChat.getGroup(guid: string): Promise<CometChat.Group>
642
+ ```