> ## Documentation Index
> Fetch the complete documentation index at: https://www.cometchat.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat experience blueprint & design system

> The cross-platform design system and experience blueprint CometChat's AI skills (and any AI coding agent) follow to build production-grade, best-in-class chat UIs end-to-end — for every UI Kit and SDK, on the customer's own brand: discovery and requirements, cloning an existing app detail by detail, when to use a UI Kit component vs build your own, design tokens, motion, responsiveness, component map, and per-app-type recipes.

This is the single reference an AI coding agent follows to build a **real** messaging experience with
CometChat — not a bare component drop, but an app with the polish of the messengers people use every
day, on the **customer's own brand**. It is **platform-generic**: the same
principles, tokens, motion, and recipes apply to **every CometChat UI Kit and SDK** — React, Angular,
React Native, iOS, Android (Kotlin XML views and Jetpack Compose), and Flutter, plus the headless
Chat/Calls SDKs for fully custom UI. (The Vue UI Kit is on an older generation, v4: the process and
design rules apply, but check its docs for what it supports before relying on any component named
here.) Process, design, and behavior rules are shared; the platform-specific parts — theming
mechanics, layout, navigation, and gotchas — are in [Per-platform notes](#per-platform-notes).
It defines the prerequisites and process, the UX principles, the design tokens, the motion and
responsiveness, the component mapping, and per-app-type recipes, plus how to build a fresh app or
retrofit an existing one end-to-end without breaking it. When the user asks for a **clone** of an
existing app, it also defines how to research that app down to the smallest detail, how to decide
**per feature** whether a UI Kit component or your own UI is the right tool, and how to make the kit
components and your own UI look and behave as one design that matches the target.

Use it with the product-scoped API indexes: this blueprint says **what to build and how it should
feel**; the exact component props, theme keys, and SDK methods come from the live docs (see
[Where to get exact APIs](#where-to-get-exact-apis)). Never invent an API — fetch it.

## Before you start (prerequisites)

Confirm these first — the same steps apply to **every** platform (React, Angular, React Native, iOS,
Android, Flutter, and Vue v4) and to the headless Chat/Calls SDKs:

* **A CometChat app + credentials in place.** App ID, Region, and Auth Key (dev) — read from the
  app's env or config; production uses **server-minted auth tokens**. Never
  invent credentials; if none are found, write placeholders and leave "add your credentials" as an
  action item.
* **The target platform/family.** Detect it from the project (or ask), then install that UI Kit — or
  the headless SDK if the design needs fully custom UI. Everything below is family-agnostic; get the
  exact component and theme names from that family's docs.
* **The archetype and feature scope.** Map the request to an [app recipe](#app-archetypes-recipes) and
  the [full feature checklist](#full-feature-checklist) — but confirm scope through
  [Discovery and requirements](#discovery-and-requirements-do-this-first) first. If unclear, default to
  a **consumer 1:1 + group messenger**.
* **The customer's brand.** Logo, app name, and palette — these replace the brand tokens; CometChat is
  the engine, not the identity.
* **Fresh build vs retrofit.** Fresh: a working app shell + the family's toolchain. Retrofit: the app
  **builds today**, a **clean git branch**, and an inventory of the current chat/UI, routing, state,
  and auth so the swap stays non-breaking.
* **Docs access.** The family's scoped LLM index plus the Docs MCP (or the docs site), so every prop
  and method is fetched, not guessed.

## How an agent must use this

Trigger this blueprint whenever the request implies a chat *experience*, not just a widget — e.g.
"build a full messaging app", "chat that looks and feels real", "a modern messenger", "team chat with
channels", or naming a well-known app to emulate.

### From a one-line request

Users rarely spell out a process. "Build me a clone of X", "make a chat like X", or "an app like X with
CometChat" is a complete request: **run everything on this page yourself** — the user should never have
to tell you to research, choose build levels, write requirements, compare, or verify. Treat the named
app as the clone target and go straight into
[Cloning an existing app](#cloning-an-existing-app-research-every-detail).

**Ask once, briefly, then work.** Send at most **one** short message of questions, only for what you
can't detect, each with a default so "go with the defaults" is a valid answer:

* **Platform / framework** — skip if there's a project in the working directory (detect it from the
  project files). Default for a new web app: React + Vite with the current React UI Kit.
* **App name** — the customer's product name to show instead of the target's. Default: a neutral
  placeholder they can rename.
* **Screenshots (optional)** — say that a few screenshots of the target's main screens, in light and
  dark, noticeably improve how close the clone gets.

Everything else takes these defaults unless the user says otherwise:

| Decision | Default |
| - | - |
| Form factor | Follow the target: desktop-first if the target is mainly desktop, mobile-first if it's mainly a phone app — and still responsive to the other |
| Theme | Light and dark, following the system setting |
| Design / colors | **Match the target:** colors, type, spacing and radii measured from it, in light and dark. The customer can switch to their own brand colors |
| Credentials | From the app's env or config; if none, placeholders plus an "add your credentials" step |
| Login | A real login screen; for a demo, a user picker over the sample users; auth tokens noted for production |
| Brand | The customer's name and an open icon set of the same style as the target — never the target's logo, name, or icons |
| Third-party packages | UI Kit / SDK only; list any package that would get closer to the target as an option |
| Scope | Everything the target has that can be built at [L0–L4](#kit-component-or-your-own-ui-decide-per-item), proposed as the default scope; L5 / L6 items listed separately with their cost |
| Dashboard features | Listed as actions for the user (e.g. enable Search), with the UI showing an honest state until they do |

**One approval, then build.** Write `cometchat-requirements.md`, and in chat give a short summary — the
proposed scope, the items that need the user's decision (L5 / L6, unverified details, dashboard
actions), and the file path — rather than pasting the whole table. A single "go" approves the
proposed scope; the user can cut or add items in the file instead. Then build, compare, and verify item
by item exactly as the rest of this page describes, and report against the plan at the end.

1. **Run discovery first — don't jump to code.** Ask the required questions, research the target
   experience, and produce a **requirements file + checklist the user approves** before building. See
   [Discovery and requirements](#discovery-and-requirements-do-this-first). This fixes the
   [archetype](#app-archetypes-recipes) (default: a **consumer 1:1 + group messenger**) and the
   third-party-package policy. **If the user names an app to clone, research that app first** — every
   screen, behavior, and visual detail, down to the tiny ones — and match *how it works*, not just how
   it looks. See [Cloning an existing app](#cloning-an-existing-app-research-every-detail).
2. **Decide, per item, kit component or your own UI.** Use the UI Kit wherever it can reach the
   target's behavior and look; build your own where it can't. Record the decision and the reason for
   every item. See [Kit component or your own UI?](#kit-component-or-your-own-ui-decide-per-item).
3. **Build the auth/session gate first** — a real login screen and session, never a hardcoded UID. See
   [Auth and session](#auth-and-session). Logged-out shows login; logged-in shows the app; logout works.
4. **Wire the complete screen set** — not just a list + a message pane. Chats, chat, **contact/group
   details, search, new chat, calls, settings** must all exist and navigate, and each opens **where
   and how the target opens it** (dialog, popover, side panel, full screen). See
   [Navigation and screens](#navigation-and-screens). **Every control the UI shows must open a working
   screen — a dead button (search/details/attach/call that does nothing) or a half-wired pane is a bug,
   not "done."**
5. **Get the layout right** — fill the viewport, the message list scrolls *internally*, the composer is
   pinned, there is **no empty gap and no over-scroll**, and it's keyboard-safe on mobile. See
   [Layout correctness](#layout-correctness).
6. **Apply the design tokens** via the family's real theming API — not the flat defaults. See
   [Design tokens](#design-tokens) and [Premium look](#premium-look). Map roles → the family's theme
   keys; theme through the kit, not ad-hoc CSS that fights it. When cloning, the tokens are **measured
   from the target**, and the kit components and your own components share them so the app reads as
   one design. See [Design sync](#design-sync-kit-components-and-your-own-ui-as-one-design).
7. **Enable the features** from the [full feature checklist](#full-feature-checklist) — some are props,
   some are Dashboard settings. Implement the archetype's whole set, not a subset.
8. **Apply motion** ([Motion and animation](#motion-and-animation)) so send/receive/typing/reactions/
   calls feel native — and, when cloning, like the target.
9. **Keep the customer's brand** — replace brand tokens + assets only; never ship CometChat branding as
   the app's identity ([Brand ownership](#brand-ownership)).
10. **Verify** against the [acceptance checklist](#verify-it-looks-and-feels-real) before finishing — a
    basic-looking UI, a dead control, an empty scroll gap, a missing login, or (for a clone) a behavior
    or visual that differs from the target without being agreed all fail the check.

### Grounding rules (non-negotiable)

* **APIs come from the docs, never memory.** Fetch component props/theme keys/SDK methods from the
  family's scoped index and page `.md` twins. If a prop can't be verified, don't use it.
* **Theme through the kit, not around it.** Use the family theming API so light/dark, RTL, and updates
  keep working. Ad-hoc CSS overrides on kit internals break on upgrade.
* **Brand is the customer's.** Their logo, name, and palette — CometChat is the engine, not the skin.
* **Non-destructive when retrofitting.** Work on a branch; preserve routing, state, and auth; swap
  region-by-region; delete only the UI you replace. See [Retrofitting](#retrofitting-an-existing-app-non-breaking).

## Discovery and requirements (do this first)

Do **not** start building before the user approves a plan, and do **not** silently build "the core"
and call it done. When the user asks for an app (especially "make it like X"), your first deliverable
is a **requirements + plan of action they approve** — then you build against an approved checklist.
This is what separates a real app from a component drop.

**For a short request** ("clone X", "an app like X"), discovery is the flow in
[From a one-line request](#from-a-one-line-request): one message of questions with defaults, a
proposed scope in `cometchat-requirements.md`, and one approval. The defaults there answer the
questions below; the user can override any of them. For a longer or open-ended request, work through
the steps below.

**Four rules that are not optional:**

1. **The plan must be exhaustive.** List *every* feature, behavior, and UI detail needed to match the
   target — not just the headline features. Include the small parity details that make or break "it
   feels like X": receipts shown or hidden, channel/DM iconography (e.g. `#` / lock vs avatar),
   threads, mentions variants, composer layout/alignment, empty/loading states, density, dark mode.
   Missing an item in the plan is the failure mode to avoid — aim to miss nothing. (The user can point
   out anything you missed; your job is that they rarely have to.)
2. **Scope is the user's decision, never yours.** Present the *whole* plan with each item tagged by how
   it's built and its effort, then let the user choose core-only, a subset, or everything. You may
   propose a default scope (as the one-line flow does), but it is only a proposal until they approve
   it. Do **not** pre-decide that "core" is enough, and do **not** ship a partial build as finished — say plainly what
   is and isn't done against the plan.
3. **Tag feasibility honestly.** Every item says how it's built — native component · prop/config ·
   dashboard extension · Calls SDK · custom code · third-party package · or **not natively possible**
   (bespoke/out). The user can't choose scope well if "not native" items look free.
4. **Match behavior, not just looks.** When the user names an app, "like X" means it *works* like X:
   features open in the same place (a centered dialog, a popover, a side panel, a new page), respond to
   the same gestures and shortcuts, and show the same states. Re-skinning the kit's default layout in
   the target's colors is not a clone. Where the kit's default placement or flow differs from the
   target, the target wins — see [Kit component or your own UI?](#kit-component-or-your-own-ui-decide-per-item).

### 1. Ask the required questions

Ask only what you can't safely infer; propose sensible defaults and let the user confirm. At minimum:

* **What experience and scope?** The kind of app and the must-have features (1:1, groups/channels,
  calls, reactions, threads, search, media/voice notes, presence, push, moderation, AI…). Map it to an
  [archetype](#app-archetypes-recipes); default to a **consumer 1:1 + group messenger** if unspecified.
* **Third-party packages policy — it changes the whole build, so the user decides.** Ask explicitly,
  or, in the one-line flow, apply the default below and list each package that would get closer as
  an option in the plan they approve:
  * **UI Kit / SDK only** — no third-party runtime dependencies; use only what the kit/SDK and the
    dashboard provide. (Safe default.)
  * **Closest-possible fidelity** — third-party packages allowed where the kit can't reach a behavior
    (for example a Lottie player for animated emoji, a charting library). List each one for approval.
  * **Middle ground** — kit/SDK first, and ask per-feature before adding any dependency.
* **UI Kit vs headless SDK** — prebuilt components, or a fully custom UI on the headless Chat/Calls SDK?
* **Platform and framework**, **auth model** (dev Auth Key vs server-minted tokens), **brand** (logo,
  name, palette), **form factors** (mobile / tablet / desktop), **dark mode**, **localization / RTL**.
* **Plan-gated / dashboard features** — which extensions (search, stickers, polls, GIFs, moderation…)
  the user will enable on their app, since several won't work until they do (see
  [Known UI Kit gotchas](#known-ui-kit-gotchas)).

### 2. Research the feature set

Don't rely on memory of what a given app "has." Research it: read the relevant CometChat docs (the
family's scoped LLM index + the Docs MCP) for what the kit/SDK actually supports, and study the target
experience the user named for the behaviors and screens it implies. Produce a concrete list — every
screen, message type, interaction, animation, **and parity detail** in scope. Go down to the details
that make it feel like the target, e.g.: does it show read receipts or not; how are channels vs DMs
labelled (`#` / lock / avatar); are threads first-class; which mention types; how is the composer laid
out; empty/loading/error states; density and dark palette. These are exactly the things that reveal a
"themed default" instead of the real app, so they belong in the plan — not discovered later by the user.

When the user names an app to clone, this step is the full research protocol in
[Cloning an existing app](#cloning-an-existing-app-research-every-detail): an inventory of every
screen, entry point, container, interaction, state, and visual token of the target.

### 3. Write a requirements file

Emit a `cometchat-requirements.md` at the project root capturing the whole plan. Tag every item with
**how** it will be built and whether it's **in scope**, so the user can approve or cut each one:

```markdown theme={null}
# CometChat build — requirements

## Decisions
- Experience / archetype: <…>
- Third-party packages: <UI Kit/SDK only | closest-possible | per-feature>
- UI approach: <UI Kit | headless SDK>
- Platform / framework: <…>   Auth: <dev key | token server>
- Brand: <name / logo / palette>   Dark mode: <y/n>   RTL: <y/n>

## Features, behaviors & parity details   (be exhaustive — include the small stuff)
| # | Item | Target behavior (entry → container → close) | Build level (L0–L6) + why | 3rd-party dep | Effort | Scope |
|---|------|---------------------------------------------|---------------------------|---------------|--------|-------|
| 1 | 1:1 messaging          | tap row → chat pane; back / Esc returns           | L0 kit as-is (Conversations, MessageList, MessageComposer) | — | S | ✅ in |
| 2 | Hide read receipts     | receipts never shown                              | L1 kit + config (message list prop)          | —          | S | ❓ ask |
| 3 | Channel `#` / lock rows| sidebar rows: `#` public, lock private, bold unread | L2 kit + slots (list-item leading/title views) | —        | M | ❓ ask |
| 4 | Global search          | shortcut or header field → centered dialog, results grouped by type → Esc / click outside | L3 kit in your container, or L4 your UI on the SDK if the grouping can't be reached | — | M | ❓ ask |
| 5 | Threads (first-class)  | "N replies" link → right side panel; close button  | L3 kit thread view in a side panel           | —          | L | ❓ ask |
| 6 | Animated/custom emoji  | inline in bubbles and picker                       | L5 third-party (Lottie + open emoji set) — or skip | lottie-web | L | ❓ ask |
| 7 | Slash commands         | `/` in composer → command popover above composer   | L4 your UI (custom parser + popover)         | —          | L | ❓ ask |
| … | (every screen, action, and parity detail from step 2)   | | | | | |

## Dashboard / account actions (the user does these)
- [ ] Enable <extension> on the app …

## Not natively possible / out of scope (bespoke or excluded)
- <item> — <why> (custom build or excluded)
```

Every row the target has goes in the table — including the parity details from step 2 — so the user
approves or cuts each with eyes open. A row that would be "not-native" must be labelled as such, not
quietly dropped. The build levels are defined in
[Kit component or your own UI?](#kit-component-or-your-own-ui-decide-per-item); the "why" is one line
(e.g. "kit search renders as a list panel; target groups results in a dialog — hosting the kit view
in a dialog matches it").

### 4. Get approval, then build one item at a time

Present the full plan and let the **user pick the scope** — core-only, a subset, or everything. It is
their call, not yours; never assume "core" is enough. Once they sign off, turn the selected rows into a
checklist and implement **one item at a time**, in order: build it, verify it (works + on-brand + no
dead controls + matches the target's behavior for that item), check it off, move to the next. Don't
batch the whole app in one pass.

When you report progress, state it **against the plan**: what's done, what's still open, and what the
user chose to leave out — never present a partial build as "finished." If the user later spots a
missing behavior, add it to the plan and treat that as a gap to avoid next time, not the normal way to
find requirements.

## Cloning an existing app (research every detail)

When the user says "build a clone of X", "make it look and work like X", or shares screenshots of an
app, the target app is the spec. The quality of the clone is decided here, before any code: what isn't
researched gets filled in with kit defaults, and kit defaults are what make a clone feel wrong. This
applies to **any** app — a consumer messenger, a team workspace, a community server, a support widget,
a marketplace inbox — not to a particular brand.

### Sources, best first

1. **What the user gives you:** screenshots, screen recordings, a Figma file, or access to the real
   app. Ask for them if the target matters and you have none; a few screenshots of the main screens,
   in light and dark, settle more questions than any description.
2. **The real app**, if you can open it (a web app in the browser tool), observed directly — click
   every control, hover, right-click, resize, and switch to dark mode.
3. **The target's public help center and docs**, which describe features, shortcuts, and settings
   precisely.
4. **Your own knowledge of the app** — only to know *where to look*. Anything you can't confirm from
   sources 1–3 is marked **unverified** in the plan and confirmed with the user, never silently filled
   with a guess or a kit default.

### The inventory (go down to the tiny details)

Record each of these for the target, per screen and per form factor (mobile / tablet / desktop):

* **Screens and navigation.** Every screen and how you get to it; what stays on screen while another
  opens (does the chat stay visible behind a dialog?); back / close behavior; deep links and URL
  changes on web.
* **Entry point → container → close, for every feature.** Where it starts (button, field, menu item,
  keyboard shortcut, gesture), what it opens in (**centered dialog**, popover, dropdown, side panel,
  bottom sheet, new page, inline expansion), and how it closes (Esc, click outside, back, close button,
  after an action). This is the detail most clones get wrong: the same feature opening in a different
  place makes the whole app feel different.
* **Lists and rows.** Grouping and section headers (collapsible? ordering?), what each row shows
  (avatar shape, name, preview, time format, unread style — bold, dot, count badge, mention badge),
  hover and selected states, row actions (swipe, hover icons, context menu), and sort order.
* **Messages.** Bubble or flat layout, alignment of own messages, grouping rules, avatar and name
  placement, timestamp placement and format, edited / deleted markers, receipts (shown or not, style),
  reactions placement, reply / quote style, thread entry ("N replies" link, avatars), link previews,
  media layout, system messages. Record avatar, name and alignment **for your own messages and
  others', in a 1:1 chat and in a group**, and write the kit's default next to the target's. The
  defaults often differ: a kit may show the avatar and name only on other people's messages in
  groups, while team apps show both on every message. When a kit setting doesn't cover a case (often
  1:1 chats and your own messages), customize the message's leading view (avatar) and header view
  (name) through the kit's slots. Do it without asking; never ship the kit default instead.
* **Calls.** Where a call starts (header buttons, a channel "huddle" button), whether it rings, and
  **where the live call shows**: full screen, a docked bar, a floating mini window, or inline. See
  [Calls and huddles](#calls-and-huddles).
* **Composer.** Layout, placeholder text, toolbar (formatting, attachments, emoji, mentions, voice),
  send button vs Enter, Shift+Enter, multiline growth, drafts, slash commands, what happens on paste
  and drag-and-drop.
* **Interactions.** Hover toolbars, long-press menus, right-click menus, swipe actions, keyboard
  shortcuts (open search, switch conversation, edit last message, mark read, close), focus order,
  scroll behavior (jump to unread, load older), double-click / double-tap behaviors.
* **States.** Empty, loading (skeletons or spinners), error, offline / reconnecting, no results,
  permission denied, first-run / onboarding.
* **Copy.** Labels, placeholders, menu items, confirmation text, empty-state text, date and time
  formats. Copy the *style* and wording pattern; use the customer's product name, not the target's.
* **Visual tokens, measured.** Colors (sample them from screenshots), font family and the type scale,
  spacing, radii, borders vs shadows, icon set style (outline / filled, stroke width), avatar shapes and
  sizes, density, light and dark palettes. See [Design sync](#design-sync-kit-components-and-your-own-ui-as-one-design).
* **Secondary surfaces.** Not only the main screens: the thread panel and its header, message info
  (read by), the reactions list, emoji and sticker pickers, context and hover menus, confirm dialogs,
  toasts, the image / video viewer, the forward picker and call screens. Each one is its own row with
  the target's design. Users judge a clone by these, and the kit opens several of them by itself
  (the hover toolbar opens message info; a reply count opens the thread). Theme each one to the
  target, rebuild it, or hide the option that opens it. A kit default left in place is not acceptable.
* **Motion, as its own list.** What animates and where: animated emoji in emoji-only messages,
  reactions and the reaction bar, how a sent message enters, menu and panel transitions, the typing
  indicator. Each entry is a row with a level. Animated emoji art the target owns is
  **not natively possible**; use an open set or say it's static.
* **Responsive behavior.** What collapses, hides, or becomes a separate screen at each width.
* **Accessibility.** Keyboard reachability, focus rings, screen-reader labels the target exposes.

Put every item in the requirements table with its observed behavior in the *Target behavior* column.
A detail you didn't research doesn't go in as a default — it goes in as **unverified** with a question
for the user.

### Legal and brand boundary

Clone the **structure, behavior, and interaction patterns**. Don't copy the target's logo, name,
trademarked artwork, illustrations, sounds, or proprietary icon set; use the customer's brand and an
open icon set of the same style. **Colors, type, spacing and radii default to the target's**, measured
from it in light and dark, so the clone looks like the app the user named. If the customer wants their
own brand colors instead, swap them into the same token source; layout and behavior stay the target's.

## Kit component or your own UI? (decide per item)

Make this decision **per item in the requirements table**, not once for the whole app. The UI Kit
components carry a lot you don't want to rebuild — real-time updates, pagination, receipts, typing,
optimistic send, retries, accessibility, localization — so prefer them wherever they can reach the
target. Build your own only where the target's behavior or layout is out of the kit's reach.

Pick the **lowest level that matches the target's behavior and look**:

| Level | What it means | Use it when |
| - | - | - |
| **L0 — kit as-is** | The kit component with default behavior | The target behaves like the kit default |
| **L1 — kit + config** | Props, feature flags, Dashboard settings, theme tokens | Only options, visibility, or colors differ |
| **L2 — kit + slots** | The kit's custom views / templates / formatters for parts of the component (row, header, bubble, empty state, menu items) | The structure matches but parts look or read differently |
| **L3 — kit in your container** | The kit component rendered inside your own dialog, popover, side panel, sheet, or route | The component's content fits but the target opens it somewhere else (e.g. search or a channel directory in a centered dialog, a thread in a side panel) |
| **L4 — your UI on the SDK** | Your own component using the Chat/Calls SDK for data and real-time events, styled with the shared tokens | The interaction model or layout can't be reached through config, slots, or a container (e.g. results grouped in a way the kit doesn't render, a custom quick switcher) |
| **L5 — third-party** | A library for something neither the kit nor the SDK provides (only under the agreed package policy) | e.g. animated emoji, charts, a rich-text editor |
| **L6 — not natively possible** | Needs backend support CometChat doesn't have | Label it, offer the closest alternative, let the user decide |

Rules:

* **Placement is never a reason to rebuild.** If the kit component's content matches and only *where
  it opens* differs, host it in your container (L3). Don't accept the kit's default placement either:
  if the target opens search as a centered dialog, a side panel is wrong even though it works.
* **Keep the message core on the kit when you can.** The message list and composer carry the most
  real-time logic; reach the target through config, slots, and templates before replacing them. If you
  must replace one, rebuild the *whole* behavior on the SDK (listeners, receipts, pagination, retries),
  not just the visuals.
* **Mixing is normal.** A typical clone is mostly L0–L3 with a handful of L4 pieces; that's the goal,
  not a compromise.
* **Never patch kit internals.** No forking the kit, no editing `node_modules`, no styling deep
  internal class names except the documented exceptions in [Known UI Kit gotchas](#known-ui-kit-gotchas).
  If a slot or prop doesn't exist for what you need, go up a level.
* **An L4 piece takes over everything the kit component did** — call buttons, presence, unread counts,
  typing — or keeps the kit piece for those parts. Replacing a kit header with your own and losing the
  call buttons is how a clone ends up with "no calling".
* **One owner per data set — no duplicate API calls.** If a kit component is mounted for a list, your
  own component must not fetch the same list again: take the selection from the kit's callbacks and
  pass objects down. When you replace a kit component, remove it rather than running both. Initialize
  and log in once (guard against React StrictMode's double effects), register each real-time listener
  once with a unique ID and remove it on unmount, and never poll what a listener delivers.
* **Every L4 piece uses the same tokens** as the themed kit, so users can't tell which parts are kit
  and which are yours (see [Design sync](#design-sync-kit-components-and-your-own-ui-as-one-design)).
* **Verify the API before choosing the level.** Whether a slot, prop, or SDK method exists comes from
  the family docs, not memory. If you can't find it, the item is a level higher than you hoped.
* **Write the level and the reason in the requirements table**, so the user sees which items are cheap
  (L0–L2) and which are real work (L4+) before choosing scope.

## Calls and huddles

Calling is off until the platform's Calls SDK is installed and enabled at init, so a clone that only
themes the UI has no working call. Plan the call experience like any other feature:

* **1:1 voice and video:** the kit's call buttons and its incoming / outgoing call screens.
* **Group calls don't ring.** Starting one posts a "meeting" message with a **Join** button in the
  group; members join from it.
* **Where the live call shows is a requirement, not a default.** If the target shows it in a docked
  bar or a mini window and the kit's call screen opens full screen, that screen is a kit default left
  in place. Join the call into your own container instead.

**Huddle / drop-in room** (a live audio session in a channel that others see and join, with no
ringing). The same five steps on every platform:

1. **Start:** a group call, audio-only, from the channel header. Send the same meeting message the
   kit's group call button sends, so the channel shows a Join entry and the conversation list updates.
   Use the group's id as the session id, so the whole channel shares one room.
2. **Join:** replace the kit's call bubble so **Join** opens your container, not the kit's
   full-screen call screen.
3. **Dock:** join the session into your own fixed-size container through the Calls SDK: generate the
   call token, then join with your container as the target. Mounting the kit's ongoing-call component
   inside your panel may not dock it, because some kits always open it full screen.
4. **Indicator:** show that a huddle is active, and who started it, from the latest meeting message.
   Show who is in it only from the Calls SDK's participant events; never guess.
5. **Leave:** leave the session and release the microphone and camera when the dock closes. Keep the
   dock mounted while the user switches channels.

Levels: L3–L4. Features the target has that CometChat doesn't (huddle threads, shared notes, screen
drawing) are **not natively possible**; list them. A call is done only when two different users on
two browsers or devices connect and hear (and see) each other.

## Auth and session

A production app has a **session**, not a hardcoded user. Build this even for a demo:

* **Gate the app on auth state.** While the SDK initializes, show a splash/skeleton; if no user is
  logged in, show a **login screen**; once logged in, show the app; on logout, return to login. Never
  drop straight into a single baked-in UID.
* **Login screen.** At minimum a field/flow to sign in the app's user (your own auth, SSO, or a user
  picker for a demo). Persist the session (the SDK stores it) so a refresh stays logged in.
* **Production auth = server-minted tokens.** In production, log in with a token your server mints;
  the dev Auth Key is for local only and must not ship in a public build. The call differs by kit:
  `CometChatUIKit.loginWithAuthToken(token)` on React, Angular, Android and Flutter;
  `CometChatUIKit.login(authToken:)` on iOS; `CometChatUIKit.login({ authToken })` on React Native.
* **Logout** clears the CometChat session and returns to the login screen.
* **Error/edge states.** Wrong credentials, network failure, or an expired session each show a clear
  message and a retry — never a blank screen or an infinite spinner.

### Empty app and sample data

A new app often has no conversations yet, so a fresh clone can look dead. That is a correct state,
not something to fix behind the user's back:

* **Never send messages, reactions, or calls, or create users and groups, on anyone's behalf without
  the user's yes** — not in the app's code, a startup "seed" script, or through the API. Messages sent
  as real users land in their real conversations.
* **Say it and ask.** Let the kit's empty states show, tell the user the app has no conversations yet,
  and offer sample data, saying exactly what you'd create: which app, how many users and groups, and
  how many messages between whom.
* **Only after a yes:** create it in a development app, outside the app's runtime code (account tools
  for users and groups; a one-off script with a server-side REST API key for messages), mark it as
  sample data, and list what was created and how to remove it.

> **Note:** A demo that logs in as a fixed UID with no login UI, no logout, and the Auth Key in the
> client bundle is a prototype, not production. Ship the gate + a login screen, and use auth tokens
> for anything real.

## Navigation and screens

A real messaging app is **many screens**, not one list + one message pane. Wire all of these and make
every affordance open a real screen (no dead buttons). The table says *what* must exist; *where and how
each one opens* comes from the target (see [Cloning an existing app](#cloning-an-existing-app-research-every-detail))
or, with no target, from the archetype's [interaction patterns](#app-archetypes-recipes):

| Screen | Built with | Must work on mobile |
| - | - | - |
| **Chats** (list, search, unread, presence, new-chat FAB) | Conversations + Search | list is the home screen |
| **Chat** (header, messages, composer) | MessageHeader + MessageList + MessageComposer | opens on tap, back returns to list |
| **Contact / group details** (profile, shared media, members, actions: mute/block/leave/report) | user/group info panel + members list | opens from the chat header |
| **Search** (across conversations, and within a chat) | Search | the search control actually filters |
| **New chat / new group** (user + group pickers) | Users + Groups + GroupMembers | the FAB opens the picker |
| **Calls** (call log + voice/video call screen) | CallLogs + Incoming/Outgoing/CallButtons | the call button starts a call |
| **Settings / profile** (theme, notifications, logout) | your screen + kit settings | reachable from a tab/menu |

**Placement follows the target.** If the target opens search in a centered dialog, a channel
directory in a dialog, a thread in a side panel, or settings on a separate page, do exactly that —
host the kit component in that container ([L3](#kit-component-or-your-own-ui-decide-per-item)) rather
than accepting the kit's default placement. The defaults below apply only when there is no target and
the archetype doesn't say otherwise.

**Mobile routing (this is where basic clones break):** use a router or an explicit screen state so
Search, Details, New Chat, Calls, and Settings each open as their **own full screen with a back
button** (or the target's mobile pattern, such as a bottom sheet) — not an overlay squeezed into a
2-pane desktop layout that silently does nothing on a phone. Default on desktop: details/search open
as the third pane or a drawer; on mobile they push over the chat. If tapping a control on a phone does
nothing, the screen wasn't wired — that is a defect to fix, not an acceptable limitation.

## UX principles

These are what separate a real messenger from a toy. Every archetype includes them unless noted.

* **Optimistic send.** The message appears instantly (pending state), then reconciles to sent →
  delivered → read. Never block the composer on the network.
* **Receipts & status.** Sent/delivered/read ticks (or equivalent), consistent and legible.
* **Typing indicator & presence.** Live "typing…" and online/last-seen where the archetype allows.
* **Message grouping.** Consecutive messages from the same sender within a short window are grouped
  (one avatar, tight spacing); a new sender or time gap starts a new group. **Date separators** and an
  **unread divider** ("New messages") are shown.
* **Smooth scrolling.** Auto-scroll to newest when at the bottom; a **scroll-to-bottom** affordance
  with an unread count when scrolled up; preserve position when loading older pages.
* **Rich media done right.** Thumbnails with aspect ratio and loading/upload progress; tap to expand;
  audio/voice notes with waveform + scrubber; file cards with type/size; link previews.
* **Reply, react, edit, delete.** Quote/reply with a jump-to-original; emoji reactions with a picker
  and counts; edit/delete with tombstones ("This message was deleted").
* **Threads** where the archetype needs them (team, community, and support apps).
* **Mentions & search.** @-mentions with autocomplete; conversation and message search.
* **Actions.** Long-press (mobile) / hover (web) message menu; swipe-to-reply on mobile.
* **Empty, loading, error, offline states** for every surface — never a blank screen; skeletons while
  loading; a clear reconnecting state.
* **Notifications.** Push when backgrounded; in-app unread badges on conversations and app icon/tab.
* **Accessibility & i18n.** Keyboard navigation, focus states, screen-reader labels, dynamic type,
  full **dark mode**, and **RTL** for RTL locales.

## Design tokens

Express the design as **semantic roles** and map each to the family's real theme keys (web: CSS
custom properties; native: the theme object). Keep two complete sets — **light** and **dark** — and
switch with the OS unless the app offers a manual toggle.

### Color roles

| Role | Purpose | Light (example) | Dark (example) |
| - | - | - | - |
| `brand` / `primary` | The customer's brand accent (buttons, active, links) | customer brand | customer brand |
| `on-brand` | Text/icon on brand | `#ffffff` | `#0e1014` |
| `bg` | App background | `#ffffff` | `#0e1014` |
| `surface` | Cards, headers, composer | `#f6f7f9` | `#16191e` |
| `surface-variant` | Hover, pressed, secondary rows | `#eceef2` | `#1f2329` |
| `bubble-in` / `on-bubble-in` | Incoming bubble + text | `#ffffff` / `#16181d` | `#1f2329` / `#eceef2` |
| `bubble-out` / `on-bubble-out` | Outgoing bubble + text | `brand` at a light tint (about 15% on `bg`) / `#16181d` | `brand` at a deep tint (about 35% on `bg`) / `#f3f4f6` |
| `text` / `text-muted` | Primary / secondary text | `#16181d` / `#5f6673` | `#eceef2` / `#9aa1ad` |
| `link` | Links & mentions | `brand` | `brand` |
| `divider` | Separators, borders | `#e3e6ea` | `#2a2f36` |
| `receipt-read` | Read-tick accent | `brand` (or a cooler accent next to it) | the same, lightened for contrast |
| `presence-online` | Online dot | `positive` | `positive` |
| `positive` / `warning` / `danger` | Semantic states (separate from brand) | `#1c7f55` / `#b5730f` / `#d64545` | `#5cc996` / `#e0a94a` / `#f07a7a` |
| `overlay` / `scrim` | Modals, media viewer | `rgba(16,18,22,.4)` | `rgba(0,0,0,.6)` |

> The neutral values are generic examples, and every accent is derived from `brand`, so with no
> target the app looks like the customer's brand, not like any existing messenger. **Replace `brand`/`primary` (and
> the bubble-out tint) with the customer's palette.** When cloning, replace *every* role with the value
> measured from the target (see [Design sync](#design-sync-kit-components-and-your-own-ui-as-one-design)).
> Keep contrast ≥ 4.5:1 for text.

### Typography

| Token | Use | Size / weight / line-height |
| - | - | - |
| `font-family` | System UI stack (or the brand font) | e.g. `-apple-system, "Segoe UI", Roboto, sans-serif` |
| `title` | Screen / chat title | 16–18 / 600 / 1.3 |
| `subtitle` | Last message, status line | 13–14 / 400 / 1.35 |
| `body` | Message text | 15–16 / 400 / 1.4 |
| `caption` | Names above bubbles, section labels | 12–13 / 500 / 1.3 |
| `timestamp` | Time & meta | 11–12 / 400 / 1.2 |

### Spacing, radius, elevation, density

| Token | Value |
| - | - |
| Spacing scale | 4-based: `4, 8, 12, 16, 20, 24, 32` |
| Radius | bubble about `8` with a tail, `12–18` without one; avatar `50%`, input `20–24`, sheet/modal `16`, cards `12` |
| Avatar sizes | list `40`, header `36`, group-tile `48`, typing `28` |
| Hit target | ≥ `44×44` (touch) |
| Elevation | header/composer subtle shadow; media viewer full scrim; sheets raised |
| Density | **comfortable** (default) vs **compact** (team/community apps): reduce vertical padding \~25% and avatar size |

### Premium look

Setting only the primary color (`--cometchat-primary-color` on web, the primary color in the theme
object on native) gives a flat, generic result (the "basic" look). A premium,
best-in-class finish needs the details. The values below are the **default** consumer-messenger finish
for when there is no reference app; when cloning, the target's measured look wins over every item here
(a team workspace, for example, usually has flat, bubble-less messages and no wallpaper):

* **Chat wallpaper, not a flat color.** Real messengers put a subtle patterned wallpaper behind the
  messages. Set `--cometchat-message-list-bg` to that wallpaper — a tiled pattern
  (data-URI or asset) or at least a tint: `bg` mixed a few percent toward `brand` (a warmer or cooler
  off-white in light, a near-black in dark), never plain white.
* **Bubbles with tails, shadow, and tight radii.** Message bubbles have a small **tail** on the
  sender's side, a subtle **drop shadow** (`0 1px .5px rgba(0,0,0,.13)`), a tight radius (about `8px`;
  use `12–18px` if you drop the tail),
  and comfortable padding. Outgoing uses `bubble-out` (a `brand` tint), incoming uses `bubble-in`.
  A flat, shadowless, tail-less rounded rectangle is exactly what reads as "basic."
* **Ticks & meta done right.** Timestamp + status ticks sit *inside* the bubble, bottom-right: single
  grey → double grey (delivered) → read in the `receipt-read` accent. Don't drop or recolor them arbitrarily.
* **Header + list rows.** The chat/app header uses the brand color with legible on-brand text; list
  rows show avatar, name, last-message preview, time, and an unread **badge** (brand-colored pill).
* **New-chat FAB** on mobile, plus hover/press states on rows and buttons — interactive things must
  look interactive.
* **Density & type.** Use the token type scale + spacing; don't cram or over-space. Match the
  reference app's density (comfortable for consumer messengers, compact for team/community apps).
* **Avatars & icons.** Circular avatars with initials fallback, a presence dot, and one consistent icon
  set. **Full dark mode** with the dark palette — not just inverted text.

The CSS variable names above are the web UI Kit's; on native, set the same things through the
family's theme and the component style objects (see [Per-platform notes](#per-platform-notes)). Pull
the exact recolorable tokens/classes from the family's **theming** and **message-bubble styling**
docs. The point is to spend the polish (wallpaper, tails, shadows, ticks, badges), not stop at the
primary color.

### Theming contract (where tokens live, and how the cascade resolves)

Overriding the primary color is not the same as owning the theme. On the web UI Kit, three facts
decide whether your tokens actually win — get them wrong and the app stays half-branded (this is the
single most common "my theme didn't apply" surprise):

* **Set the brand tokens on BOTH the kit wrapper and the document root.** The kit reads most tokens
  from the `.cometchat` wrapper, but some values — notably the accent baked into generated icon assets —
  are read from `:root` / `document.documentElement`. Declare the full brand set (primary + the extended
  primary ramp `50`–`900` + highlight icon/text/border + button/FAB backgrounds) on **both** `:root`
  (and `html`) **and** `.cometchat`. Tokens set only on `.cometchat` leave the root-read values on the
  kit default.
* **Win the cascade on purpose.** The kit ships its own rules on `.cometchat` / `[data-theme]`.

  * **React v7** declares them inside `@layer cometchat`, so any unlayered rule of yours already wins,
    whatever the stylesheet load order. If your own CSS is layered (for example Tailwind's `@layer`),
    extra specificity won't help: declare the order with your layer last
    (`@layer cometchat, app;`) or put the token overrides outside any layer.
  * **Angular** ships unlayered CSS, so raise specificity deliberately: the doubled-class
    `.cometchat.cometchat { … }` for tokens, and the same-element `.cometchat[data-theme="dark"] { … }`
    (not a descendant selector) for the dark set.

  Either way, define every token in the base rule, then redefine only what changes under dark.
* **Some icons are a CSS `filter`, not a token — so you override the filter.** The composer /
  attachment / emoji icons are `<img>` assets recolored by a **hardcoded** CSS `filter`
  (`brightness(0) … hue-rotate(…deg) …`) that no `--cometchat-*` variable touches. Brand them by
  overriding that `filter` on the specific rules that carry it, and **solve the filter numerically**
  rather than guessing: draw the icon to a `<canvas>` with a candidate `ctx.filter`, read the average
  pixel, and sweep `hue-rotate` / `invert` / `saturate` to minimise distance to your brand color. Full
  recipe and selector list in [Known UI Kit gotchas](#known-ui-kit-gotchas).

Treat theming as a **contract** — where tokens live, plus how specificity resolves — not a single
variable. (Native families theme through the platform theme object instead; the "both scopes" and
"filter icons" points are web-specific.)

## Design sync: kit components and your own UI as one design

A clone usually mixes themed kit components with a few pieces of your own UI. Users must not be able to
tell which is which, and both must match the target. Do it in this order:

1. **Measure the target.** From screenshots or the real app, sample the colors for every
   [color role](#color-roles) in light and dark, and note the font family, type scale, spacing, radii,
   borders vs shadows, icon style, avatar shape and size, and density. Record them in the requirements
   file.
2. **One token source.** Put the measured values in one place (CSS custom properties on web; a theme
   object on native) and derive everything from it. Never hard-code a color or size in a component.
3. **Theme the kit from those tokens** through the family's theming API, including the parts that are
   easy to miss: menus and context menus, dialogs, the emoji keyboard and pickers, reaction chips,
   date separators, unread dividers, empty and error states, avatars, badges, and the icons recolored
   by a filter (see [Theming contract](#theming-contract-where-tokens-live-and-how-the-cascade-resolves)).
4. **Build your own UI from the same tokens** — the same colors, type scale, spacing, radii, icon set,
   hover and focus states, and motion — so a custom dialog or quick switcher sits next to a kit list
   without a visible seam.
5. **Use kit slots for in-component differences.** If a row, header, or bubble must look different,
   use the kit's custom views/templates (L2) styled with the shared tokens, rather than overriding
   internal classes.
6. **Compare side by side.** For each screen and state — light and dark, mobile and desktop — put a
   screenshot of the target next to a screenshot of the build and list every difference: layout,
   spacing, color, type, icon, copy, placement, behavior. Fix them and repeat until each remaining
   difference is either fixed, agreed with the user, or recorded as not reachable (with the reason) in
   the requirements file.

If the kit can't reach a visual detail through tokens or slots, move that item up a
[level](#kit-component-or-your-own-ui-decide-per-item) or record the gap — don't fight the kit with
fragile overrides.

## Motion and animation

Match the real product's feel. Durations are guidance; respect `prefers-reduced-motion` (and the
platform's reduce-motion setting) by dropping to instant/opacity-only.

| Interaction | Motion | Duration / easing |
| - | - | - |
| Message send | New bubble fades + rises a few px into place; status ticks cross-fade pending→sent | 150–200ms ease-out |
| Message receive | Fade/slide in from the incoming side; subtle list shift | 150–200ms ease-out |
| Typing indicator | Three dots looping (scale/opacity) | \~1.2s loop |
| Reaction | Emoji pops with a slight overshoot (spring) | 180–260ms spring |
| Long-press / hover menu | Scale-up + fade from the anchor | 120–160ms ease-out |
| Swipe-to-reply | Bubble tracks the finger; icon reveals past threshold; snaps back | interactive + 150ms snap |
| Scroll-to-bottom button | Fade/scale in when scrolled up; unread count badge | 120ms |
| Screen/route change | Native push/replace (mobile); slide/fade (web) | platform default |
| Incoming call | Pulsing avatar/ring; slide-up call screen | \~1s ring loop |
| Skeleton loading | Shimmer sweep on placeholders | \~1.2s loop |

On iOS/Android/Flutter, prefer the **platform-native** transition primitives; on web, prefer
transform/opacity (GPU-friendly) over layout-animating properties.

### Sending feels smooth (one change, not two)

In a real messenger a sent message appears once, and only its status changes (clock, then ticks). In a
clone it often appears, then jumps or re-renders when the server confirms it. The cause: the kit shows
a pending copy keyed by its `muid`, then swaps in the confirmed message with a server `id`, and the
server's `sentAt` can differ from the local one. Where the kit keys rows by id, the row (and its date
separator) mounts again.

* Anything stateful in a bubble (an entrance animation, a loaded image, animated emoji, a custom
  view's state) must survive that remount. Key your own state by `muid` (fall back to `id`), and make
  custom views render the same result from the same message, with no "first render" effects.
* An entrance animation runs once per `muid`, never again on the confirmed copy. Don't detect new rows
  by watching the DOM, and never patch kit markup with scripts; change it through the kit's templates,
  custom views and props.
* **Check it:** send a text, an emoji-only message and an image, and record the last row's position and
  size from send until it's confirmed. Only the status icon may change. If a remount still shows and
  you can't hide it through the kit's API, report it as a known kit limitation with the version.

## Layout and responsiveness

| Breakpoint | Layout |
| - | - |
| Mobile `< 600px` | **Single pane**: conversation list → push-navigate to the chat; full-screen chat; bottom tab bar for sections; sticky composer with keyboard-avoidance; respect safe-area insets. |
| Tablet `600–1024px` | **Two pane**: list (left) + active chat (right). |
| Desktop `> 1024px` | **Three pane**: nav rail / conversation list / chat pane, with a collapsible **details** drawer (profile, group members, shared media, search). |

Rules: the chat pane always shows a header, a scrollable message list, and a pinned composer. The list
column keeps search + new-chat affordances. Never let the body scroll horizontally; media and the
message list scroll within their own containers.

### Layout correctness

The rules below are for the **web** UI Kits (React, Angular). Native apps have the same goals — the
message list scrolls on its own, the composer stays pinned above the keyboard, nothing hides under the
notch or system bars — but reach them through the platform's own tools; see
[Per-platform notes](#per-platform-notes).

The #1 reason a web clone looks broken — an empty gap under the messages, the **whole page scrolling**, or
the composer floating — is flex/height mistakes. Follow these exactly:

* **Full-viewport root.** `html, body, #root { height: 100%; margin: 0 }`; the app shell uses
  **`height: 100dvh`** (dynamic viewport height — accounts for mobile browser chrome, so there is no
  empty strip at the bottom). Reset the starter's `#root` (`max-width: none; padding: 0; width: 100%`).
* **The chat column is a flex column that fills its parent and clips:** `display: flex;
  flex-direction: column; height: 100%; min-height: 0; overflow: hidden`.
* **The message list flexes and scrolls internally:** give it `flex: 1 1 auto; min-height: 0`. The
  `min-height: 0` is exactly what stops the list from pushing the layout taller and leaving an empty
  gap / making the whole document scroll. Header and composer are `flex: 0 0 auto` (composer pinned to
  the bottom).
* **Only the message list scrolls — never the page body.** If you see the whole screen scroll, or a gap
  below the last message, a flex parent is missing `min-height: 0` / `overflow: hidden`, or the root
  isn't `100dvh`. Fix that before shipping.
* **Keyboard-safe on mobile.** Use `100dvh` (not `100vh`) so the composer stays above the on-screen
  keyboard; keep the composer sticky. Never put `transform` or `filter` on an ancestor — it clips the
  kit's fixed overlays (emoji picker, context menus, call screen).

## Component map

Use these real UI Kit components (names per family may vary slightly — confirm in the family docs):

| App region | CometChat component(s) |
| - | - |
| Conversation list (with search, unread, presence) | **Conversations**, **Search** |
| Chat header (title, presence, call buttons, actions) | **MessageHeader**, **CallButtons** |
| Message stream (grouping, receipts, date separators) | **MessageList** + the **bubble** set (text/image/video/audio/file/**voice-note**/poll/card/sticker/collaborative) |
| Composer (text, attachments, emoji, voice, mentions) | **MessageComposer** |
| Reactions | **Reactions**, **ReactionList** |
| Replies / threads | No single thread component: compose a thread panel from **ThreadHeader** (parent message, close), **MessageList** for the replies (pass the parent message) and **MessageComposer** (pass the parent message id). **ThreadView** is the "N replies" entry on a bubble that opens it |
| Groups & membership | **Groups**, **GroupMembers**, **group-action** bubbles |
| People / new chat | **Users** |
| Calls (voice/video) | **IncomingCall**, **OutgoingCall**, **CallButtons**, **CallLogs**, call bubbles |
| Pinned / saved / message info | **PinnedMessages**, **SavedMessages**, **MessageInformation** |
| AI assistant surface | **AIAssistantChat** |
| Moderation affordance | **FlagMessageDialog** |

When a design needs a layout the prebuilt components don't cover, first check whether hosting the
component in your own container or using its custom views reaches it; if not, build the custom UI on
the **Chat/Calls SDK** (headless) — but reuse these tokens, motion, and principles so it still feels
consistent. See [Kit component or your own UI?](#kit-component-or-your-own-ui-decide-per-item).

## App archetypes (recipes)

Each recipe = layout + components + the features to enable + token/vibe deltas. All inherit the
[UX principles](#ux-principles).

The archetypes below are described by their **characteristics**, not by any one branded app — pick the
closest fit in [discovery](#discovery-and-requirements-do-this-first). If the user names an app to
emulate, the archetype is only the starting point: the researched target
([Cloning an existing app](#cloning-an-existing-app-research-every-detail)) overrides every layout,
interaction, and visual below. Each archetype lists its usual **interaction patterns** — where things
open and how they're reached — so an app built without a reference still behaves like its category,
not like the kit's default layout.

### Consumer 1:1 + group messenger (default)

* **Layout:** mobile single-pane / desktop 3-pane. Chat list with avatars, last message, time, unread.
* **Components:** Conversations, MessageHeader (+CallButtons), MessageList (+bubbles), MessageComposer,
  Reactions, a thread panel (optional: ThreadHeader + MessageList + MessageComposer),
  Groups/GroupMembers, IncomingCall/OutgoingCall.
* **Features:** 1:1 + groups, media + docs, **voice notes**, reactions, reply, delivery/read ticks,
  typing, presence/last-seen, voice/video calls, push, disappearing messages (optional), starred/saved.
* **Vibe:** rounded bubbles, outgoing tinted, read-tick accent, comfortable density.
* **Interaction patterns:** the chat list is home; search sits at the top of the list and filters it
  in place, then shows message results below; new chat from a floating button or header icon opens a
  contact picker (full screen on mobile); long-press a message → reaction bar above + action menu;
  swipe to reply; tap the chat header → contact/group info as its own screen with shared media;
  in-chat search from the header menu with up/down result navigation.

### Large-community / channels messenger

* Large groups/channels, message **folders/filters**, fast search, stickers/GIFs, reactions, silent
  send, edit history, threads. Denser than the consumer default; snappy motion.
* **Interaction patterns:** folder tabs above the list; global search covers chats, public channels,
  and messages in one results view with sections; channel info shows subscriber count and a join
  button for non-members; right-click / long-press context menus on chats and messages.

### Minimal personal messenger

* Minimal, high-contrast bubbles with tails, **bubble-anchored quick reactions**, inline media, typing
  bubble. 1:1 focus + small groups. Comfortable density; understated motion.
* **Interaction patterns:** double-tap or long-press a bubble for quick reactions anchored to it;
  details from the header; few visible controls, most actions behind long-press.

### Team workspace (channels + DMs)

* Workspaces → channels + DMs; **threads-first**; rich composer (formatting, code, attachments);
  mentions; left sidebar (channels/DMs), desktop 3-pane, compact density.
* **Interaction patterns:** a **quick switcher** opened by a keyboard shortcut (Ctrl/Cmd+K) in a
  centered dialog to jump to any channel or person; **global search** in a centered dialog or a
  top-bar field with results grouped by type (messages, channels, people, files) and filters; a
  **channel directory** ("browse channels") dialog listing public channels with member counts, preview,
  and join; collapsible sidebar sections (starred, channels, direct messages) with bold unread rows and
  mention badges; **threads in a right side panel** with the channel still visible; a **hover toolbar**
  on messages (react, reply in thread, more); flat messages (avatar + name + time, no bubbles) grouped
  by sender; channel header with name, topic, and member count opening a details dialog; Up arrow to
  edit your last message; Enter sends, Shift+Enter adds a line; avatar and name on **every** message
  run, including your own and in DMs; **huddles** (a live audio session in a channel that others see
  and join, without ringing) docked at the bottom of the sidebar and expandable into a window, built
  with the [huddle steps](#calls-and-huddles). On mobile see
  [Mobile equivalents](#mobile-equivalents-of-desktop-patterns).

### Community server (voice + text)

* Servers → channels; strong **presence**; voice channels; dense, **dark-first**; roles/mentions;
  reactions; inline media.
* **Interaction patterns:** a server rail on the far left, channel categories that collapse, a member
  list on the right grouped by role and online state, role-colored names, hover toolbar on messages,
  user profile popover on avatar/name click, a quick switcher by keyboard shortcut. On mobile see
  [Mobile equivalents](#mobile-equivalents-of-desktop-patterns).

### Support / live-chat

* Embedded widget or full-screen; 1:1 user↔agent; quick replies, canned responses, bot→agent handoff,
  transcript, post-chat rating. Minimal chrome; brand-forward.
* **Interaction patterns:** a launcher button in a corner opens the chat as a floating panel (full
  screen on mobile); optional pre-chat form; quick-reply chips above the composer; "agent is typing"
  and estimated wait; end-chat confirmation and rating in the same panel.

### Community / social

* Feeds + DMs; large public groups; moderation (flag/ban), roles; discovery/search.
* **Interaction patterns:** DMs reached from an inbox icon in the app's main navigation; a group
  directory with search and join; report and block from message and profile menus.

### Marketplace / dating

* 1:1 with media, safety (block/report/moderation), read receipts optional, presence optional; clean,
  trust-forward.
* **Interaction patterns:** conversations start from a listing or profile ("Message" button), so the
  chat header shows that context (item card or profile); safety actions (block, report) are one tap
  from the header; the inbox may filter by listing or match.

## Full feature checklist

"Full feature" means the agent has enabled all of these that apply to the archetype (some are props,
some are Dashboard settings — verify each in the docs):

* **Messaging core:** 1:1, groups, send/edit/delete, reply/quote, optimistic send, receipts, typing,
  presence, grouping, date separators, unread divider.
* **Rich media:** images, video, audio, files, **voice notes**, stickers/emoji/GIF, link previews,
  thumbnails + progress, media viewer.
* **Engagement:** reactions, mentions, polls, pinned messages, saved/starred, threads.
* **Groups & moderation:** create/manage groups, roles/scopes, add/remove/ban, report/flag.
* **Calls:** 1:1 and group voice/video, incoming/outgoing UI, call logs. Calling is off until the
  family's Calls SDK is installed and calling is enabled at init — a themed UI with call buttons that
  do nothing is not calling. Group calls are joined, not rung, so drop-in rooms ("huddles") are group
  calls plus your own presence indicator.
* **Discovery:** conversation + message search, new-chat/user picker.
* **Notifications:** push (FCM/APNs), in-app badges, mute/preferences.
* **Personalization:** dark mode, density, per-conversation settings.
* **Accessibility & i18n:** keyboard, screen-reader, dynamic type, RTL, localization.
* **Security/production:** server-minted auth tokens, blocked users, data handling.

## Building a fresh app (end-to-end)

1. **Discover & agree scope** — run [Discovery and requirements](#discovery-and-requirements-do-this-first):
   ask the required questions (incl. the third-party-package policy), research the feature set (for a
   clone, the full [target inventory](#cloning-an-existing-app-research-every-detail)), pick a
   [build level](#kit-component-or-your-own-ui-decide-per-item) for every item, write
   `cometchat-requirements.md`, and get the checklist approved **before** writing code.
2. **Install** the CometChat UI Kit for the target framework; wire `init → login` (dev auth key for
   local, **server-minted auth tokens** for production).
3. **Apply tokens:** set the light + dark token sets via the family theming API — measured from the
   target when cloning ([Design sync](#design-sync-kit-components-and-your-own-ui-as-one-design)); drop
   in the customer's brand + logo.
4. **Compose the layout** for the form factor and archetype using the component map, with every
   feature opening in the target's container (dialog, popover, side panel, page).
5. **Enable features** from the approved checklist, **one item at a time** (props + Dashboard settings),
   at the agreed build level, comparing each against the target before moving on.
6. **Wire calls & push** if the archetype includes them.
7. **Add motion & responsiveness** per the specs above (or the target's).
8. **Verify** with the acceptance checklist and, for a clone, the side-by-side comparison; fix; ship.

## Retrofitting an existing app (non-breaking)

1. **Branch**; keep a clean tree. Never force-delete non-chat code.
2. **Inventory** the app's current chat/UI, routing, state, and auth.
3. **Map** each existing chat surface to a CometChat component (or headless SDK), choosing a
   [build level](#kit-component-or-your-own-ui-decide-per-item) that keeps the app's current
   behavior: where each feature opens, its shortcuts, and its states. The existing app is the target.
4. **Layer the theme:** apply the token roles onto the app's existing brand so the kit matches the app,
   not the reverse.
5. **Swap region-by-region** behind the existing routes and state — list, then chat pane, then calls —
   verifying the build after each. Preserve auth and navigation.
6. **Remove only the UI you replaced**; leave everything else intact.
7. **Verify** parity with the checklist; confirm the build passes and there are no console errors.

## Known UI Kit gotchas

Verified traps a generic design doc won't warn you about — each has cost real build time. Check them
explicitly. The items below are **web UI Kit** (React v7, and Angular where it shares the CSS-variable
theming); component and prop names are React's. Native gotchas are in
[Per-platform notes](#per-platform-notes).

* **Off-brand icons that no token fixes (web).** The composer / attachment / emoji icons are `<img>`
  data-URIs recolored by a hardcoded CSS `filter` (`… hue-rotate(235deg) …` = the kit's default
  accent), **not** a `--cometchat-*` token — so brand tokens leave them the default color, most visibly
  in **dark mode**. Idle composer icons use a neutral grey filter; the accent filter applies on
  **hover and active** states. **Fix:** override the `filter` on the rules that carry the accent.
  Selectors (React UI Kit v7.2), each followed by ` .cometchat-message-composer__button-icon` unless
  noted:
  `.cometchat-message-composer__attachment-button:hover`, `__emoji-button:hover`,
  `__sticker-button:hover`, `__voice-button:hover`;
  `.cometchat-message-composer__attachment-button--active`, `__emoji-button--active`,
  `__sticker-button--active`;
  `.cometchat-message-composer__ai-button:hover`, `__ai-button--active`;
  `.cometchat-message-composer__attachment-option-icon` (on its own, no descendant);
  `.cometchat-emoji-keyboard__tab--active .cometchat-emoji-keyboard__tab-icon`.
  Leave the `--disabled:hover` rules (they reset to grey) and `__voice-button--active` (red while
  recording) alone. Solve the filter for
  your brand color by canvas-sampling (see [Theming contract](#theming-contract-where-tokens-live-and-how-the-cascade-resolves)).
  Worked example (a teal; solve your own brand the same way):
  `brightness(0) saturate(1) invert(.4) sepia(.6) saturate(6) hue-rotate(120deg) brightness(.85) contrast(1)`
  (measured rgb ≈ 1,125,104).
* **Search needs the Search feature enabled on the app's plan.** `CometChatSearch` (conversation +
  message search) returns an error (HTTP 402) until **Search is enabled on the app's plan**
  (dashboard), and the component itself shows no message about it. Correctly wired search still returns nothing until then. **Fix:** always pass
  `onError` and surface the gate to the user instead of a dead search box, and tell the customer to
  enable Search on their plan. Never assume "search works" because the component rendered.
* **Message search is a component.** On **React**, `CometChatMessageHeader` already shows a search
  button (`showSearchOption`, on by default); handle `onSearchOptionClicked` to open search, or set
  `showSearchOption={false}` if you add your own trigger, so the header doesn't show two. The other
  kits' headers have no search button. Either way, use **`CometChatSearch`** and open it from
  **wherever the target opens search**: the conversation list's `onSearchBarClicked` and a header `auxiliaryButtonView` trigger are
  the kit's default entry points, but you can equally render `CometChatSearch` inside your own centered
  dialog, popover, or side panel opened by a top-bar field or a keyboard shortcut. Route results with
  `onConversationClicked` / `onMessageClicked` → `CometChatMessageList`'s `goToMessageId`. If the target
  groups results in a way the component doesn't render, build that view on the SDK instead
  ([L4](#kit-component-or-your-own-ui-decide-per-item)). New chat uses **`CometChatUsers`**. Confirm
  exact component/prop names in the family docs before wiring.
* **Give the details panel an explicit way in.** Tapping the avatar or name
  (`CometChatMessageHeader`'s `onItemClick`) is easy to miss, so don't make it the *only* way in — add
  an explicit info button (e.g. in `auxiliaryButtonView`) so the details panel is always reachable. A
  details screen you can't open is a dead control.
* **Verify in DARK mode, not just light.** Several of the above (especially the icon filter) look fine
  in light and regress in dark. Test the composer, attachment menu, emoji keyboard, and reactions with
  the theme set to dark before calling it done.
* **Don't put `transform` / `filter` on an ancestor of the kit.** It clips the kit's fixed overlays
  (emoji picker, context menus, call screen). Keep those off the app shell.

## Per-platform notes

Everything above the token *values* is shared. This section covers what differs per platform: how
the theme is applied, how layout and navigation work, and the traps we've hit. Exact class, prop, and
method names still come from each family's docs — the names here are pointers, current at the time of
writing; confirm them before use.

### Theming per platform

| Platform | How the token roles are applied | Watch out for |
| - | - | - |
| **React, Angular** | CSS custom properties (`--cometchat-*`) | The [Theming contract](#theming-contract-where-tokens-live-and-how-the-cascade-resolves): set tokens on both `:root` and `.cometchat`, win the cascade on purpose, override the icon `filter` |
| **React Native** | Wrap the app in `CometChatThemeProvider`; pass `light` / `dark` color overrides and per-component style objects through its `theme` prop | Colors as hex values; values deep-merge with defaults, so set both light and dark |
| **iOS** | Global `CometChatTheme` colors and `CometChatTypography`, plus each component's style | Set the theme **before** `CometChatUIKit.init()`; provide dynamic colors for light and dark |
| **Android (Kotlin XML views)** | A theme extending `CometChatTheme.DayNight` in `themes.xml` with `cometchat*` attributes, or `CometChatTheme.set*()` in code | Dark mode via `values-night/themes.xml`; programmatic overrides beat activity and application themes |
| **Android (Jetpack Compose)** | Wrap content in the `CometChatTheme { }` composable with a `CometChatColorScheme`, typography, and shapes | Provide a dark color scheme based on `isSystemInDarkTheme()` |
| **Flutter** | Register `CometChatColorPalette`, `CometChatTypography`, and `CometChatSpacing` in `ThemeData.extensions` | Register on **both** the light and dark `ThemeData`, or one mode keeps kit defaults; assigning `extensions` replaces the ancestor's, so use `CometChatTheme.mergeThemeExtensions`; widget backgrounds need each widget's own style |

On native there is no CSS cascade and no icon `filter`: the kit's icons are tinted through the theme
and component styles. If the theme doesn't reach an icon, pass your own icon through the component's
icon or style property, if the family docs list one.

### Layout and navigation per platform

| Platform | Keyboard and safe areas | Navigation |
| - | - | - |
| **Web (React, Angular)** | [Layout correctness](#layout-correctness): `100dvh`, flex with `min-height: 0`, internal scrolling | A router (URL per conversation) or explicit screen state; dialogs and side panels for desktop patterns |
| **React Native** | `react-native-safe-area-context` for insets; keyboard avoidance around the composer (check the kit docs for what the message composer already handles before adding your own) | React Navigation (stack for list → chat → details; tabs for sections; modal presentation for dialogs and sheets) |
| **iOS** | Respect the safe area; keep the composer above the keyboard (keyboard layout guide or the kit's own handling) | A navigation stack for push screens; sheets for dialog-style features; tab bar for sections; split view on iPad |
| **Android** | Edge-to-edge with window insets; resize for the keyboard so the composer stays visible | Activities/Fragments with the Navigation component, or Compose Navigation; bottom sheets for menus |
| **Flutter** | `SafeArea`; `Scaffold` resizing for the keyboard | `Navigator` or a router package; `showModalBottomSheet` / dialogs for sheet- and dialog-style features |

On every platform: the message list scrolls on its own, the composer stays visible with the keyboard
open, nothing sits under the notch, status bar, or home indicator, and back (gesture, hardware button,
or Esc on web) closes the top-most screen, sheet, or dialog first.

### Mobile equivalents of desktop patterns

When a target is desktop-first, its mobile version (or the platform convention, if it has none)
decides how each pattern works on a phone. Research the target's mobile app if it exists; otherwise
use these:

| Desktop pattern | Mobile equivalent |
| - | - |
| Hover toolbar on messages | Long-press → reaction bar + action sheet |
| Right-click context menu | Long-press menu or action sheet |
| Keyboard quick switcher (Ctrl/Cmd+K) | A "jump to" search screen from a top-bar button or a tab |
| Centered search dialog | A full-screen search screen pushed over the current one |
| Channel directory dialog | A full-screen list with search and join |
| Thread in a right side panel | Thread as its own pushed screen, with the parent message on top |
| Details dialog or right drawer | A pushed details screen (or a sheet on iPad / large screens) |
| Collapsible sidebar sections | Sections in the home list (collapsible if the target has it), or tabs |
| Hover states and tooltips | Pressed states; labels shown in menus instead of tooltips |
| Enter to send, Shift+Enter for a new line | A send button; the return key adds a line unless the target sends on return |
| Drag-and-drop files | The attachment button and the system share sheet |
| Swipe actions (mobile-only) | Hover icons or a context menu on desktop |

### Localization per platform

The API differs by family — don't assume one name everywhere: React, Angular, iOS, and Android use
`CometChatLocalize`; React Native uses `CometChatI18nProvider` with the `useCometChatTranslation`
hook; Flutter uses `CometChatLocalize` too, plus the kit's `Translations.delegate` in
`localizationsDelegates` (check the version's docs — this has been changing). Set the language, then check right-to-left layouts in an RTL locale.

### Native gotchas

* **React Native with Expo needs a development build.** Expo Go isn't supported because the UI Kit
  uses native modules; build a dev client. Calls and push also need native setup, so start the native
  build early rather than at the end.
* **React Native: install every peer dependency** the integration guide lists (for example
  `react-native-gesture-handler`, `react-native-svg` and `react-native-video`) — a missing one fails at
  runtime, not at install.
* **iOS: theme before init.** Theme values set after `CometChatUIKit.init()` don't reach components that
  are already created.
* **Flutter: theme both modes, and merge extensions.** A palette registered only on the light
  `ThemeData` leaves dark mode on kit defaults; replacing `extensions` drops the ones an ancestor set.
* **Android: day/night resources.** Brand colors set only in `values/themes.xml` stay unbranded in dark
  mode unless `values-night` overrides them too.
* **All native platforms: test on a real device or emulator** for keyboard, safe-area, permission
  (camera, microphone, notifications, photos), and push behavior — simulators and previews miss them.
* **Verify in dark mode and at large text sizes** (Dynamic Type, font scale): fixed heights in custom
  rows and headers clip text.

## Verify it looks and feels real

Ship only when all pass:

* **Login works:** logged-out shows a login screen; logging in enters the app; logout returns to login;
  refresh stays signed in. No hardcoded UID, no Auth Key in a public production build.
* **No layout bugs:** the message list fills the space and scrolls **internally**; the composer is
  pinned; **no empty gap under the messages and no whole-page/over-scroll**; correct with the mobile
  keyboard open (`100dvh`).
* **Every control works on mobile:** tapping search filters; the chat header opens **contact/group
  details** (profile, shared media, members); the FAB opens **new chat**; the call button starts a
  **call**; settings is reachable. **No dead buttons.**
* **Premium look, not flat:** when there's no target, patterned/tinted chat wallpaper; bubbles have
  tails + subtle shadow; ticks grey, then the `receipt-read` accent on read; unread badges; avatars + presence; proper density —
  it doesn't look like the default demo. When cloning, the target's look replaces these.
* **Clone parity (when the user named an app):** every item in the requirements table is built at its
  agreed level or explicitly left out; every feature opens in the same place, through the same entry
  points and shortcuts, and closes the same way as in the target; side-by-side screenshots of each
  screen and state (light + dark, mobile + desktop) show no unagreed difference; kit components and
  your own UI share the same tokens with no visible seam; no unverified detail was shipped as a guess.
* **Message details match:** open a 1:1 chat and a group and compare your own and others' messages
  with the target: avatar, name, alignment, grouping, timestamps, receipts.
* **Live calls show in the target's container:** docked, mini window or full screen, as recorded.
* **Secondary surfaces match:** open each one (thread, message info, reactions list, pickers, menus,
  dialogs, viewer, call screens) and compare it with the target; none is left in the kit's default look.
* **Motion actually moves:** for every motion row, two frames about 300 ms apart differ; a static
  fallback counts as not done.
* **Sending is one visual change:** a sent message appears once and only its status icon changes
  (see [Sending feels smooth](#sending-feels-smooth-one-change-not-two)).
* Bubbles grouped correctly; date separators + unread divider present.
* Optimistic send; sent/delivered/read states; typing; presence.
* Smooth auto-scroll + scroll-to-bottom with unread count.
* Media thumbnails + progress; voice notes; link previews.
* Reactions, reply/quote (with jump-to-original), edit/delete tombstones.
* Search returns results **or an honest plan-gated state** (never a silent dead box — Search can 402);
  mentions work; long-press/hover menu; swipe-to-reply (mobile).
* Empty / loading (skeleton) / error / offline states on every surface.
* Responsive at mobile / tablet / desktop; no horizontal body scroll; safe areas + keyboard-avoidance.
* **Native:** themed in light and dark through the platform's theme API (not per-screen hacks); back
  gesture / hardware back closes the top-most sheet or screen; desktop patterns use their
  [mobile equivalents](#mobile-equivalents-of-desktop-patterns); checked on a real device or emulator.
* Full dark mode — including **on-brand icons** in the composer / attachment menu / emoji keyboard
  (these are recolored by a hardcoded filter, not a token; see [Known UI Kit gotchas](#known-ui-kit-gotchas));
  RTL for RTL locales; `prefers-reduced-motion` respected.
* Customer brand + logo applied; no CometChat branding as the app identity.
* Push + unread badges; calls (if in scope) ring and connect **between two different users on two
  browsers or devices**, with audio (and video) both ways. If you couldn't run that check, report
  calling as built but not verified, never as working.
* **No duplicate requests:** opening the app, opening a conversation, and sending a message each make
  every request once in the network log (twice only under React's development StrictMode, with the
  guards making the second a no-op).
* **No data created without asking:** no messages, reactions, calls, users, or groups were created on
  anyone's behalf unless the user said yes; any sample data is listed with how to remove it.
* Build passes; no console errors; APIs used all exist in the docs.

## Brand ownership

The app's **identity is the customer's** — their name, logo, colors, and tone. CometChat is the
messaging engine underneath. Replace the `brand`/`primary` tokens, the bubble-out tint, and the logo/
app name; keep the component structure, principles, motion, and layout. Do not present CometChat's own
branding as the product's.

## Where to get exact APIs

This blueprint is the *what* and *how it feels*; get the exact *how* from the live docs:

* **Per-product LLM indexes** — the scoped routing indexes for each UI Kit / SDK (append `.md` to any
  docs URL for its clean twin), and the site-wide [llms.txt](https://www.cometchat.com/docs/llms.txt).
* **Theming** — your family's theming guide for the real theme keys these token roles map to:
  [React](https://www.cometchat.com/docs/ui-kit/react/theming.md), [Angular](https://www.cometchat.com/docs/ui-kit/angular/customization/theming.md),
  [React Native](https://www.cometchat.com/docs/ui-kit/react-native/theme.md), [iOS](https://www.cometchat.com/docs/ui-kit/ios/theme-introduction.md),
  [Android](https://www.cometchat.com/docs/ui-kit/android/theme-introduction.md), [Flutter](https://www.cometchat.com/docs/ui-kit/flutter/theme-introduction.md).
* **Localization** — [React](https://www.cometchat.com/docs/ui-kit/react/localization.md), [Angular](https://www.cometchat.com/docs/ui-kit/angular/customization/localization.md),
  [React Native](https://www.cometchat.com/docs/ui-kit/react-native/localize.md), [iOS](https://www.cometchat.com/docs/ui-kit/ios/localize.md),
  [Android](https://www.cometchat.com/docs/ui-kit/android/localize.md), [Flutter](https://www.cometchat.com/docs/ui-kit/flutter/localize.md).
* **Components** — the component's page in your family for verified props and defaults — e.g.
  [Conversations](https://www.cometchat.com/docs/ui-kit/react/components/conversations.md). Component names are consistent across
  families; confirm the exact props per family.
* **Skills & MCP** — [Agent Skills](https://www.cometchat.com/docs/agent-skills.md) to install the CometChat skills, and the
  [Docs MCP](https://www.cometchat.com/docs/mcp-server.md) for live docs inside the agent.
* **Key concepts** — [Fundamentals: Key Concepts](https://www.cometchat.com/docs/fundamentals/key-concepts.md).

Never answer a prop or method from memory — fetch it from the pages above.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.