> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-skills-v5-temp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Group Chat Setup

> Create public, password-protected, and private groups; add, remove, and manage members with role-based permissions; join, leave, and transfer ownership using the CometChat UI Kit.

## Goal

By the end of this guide you will have a working group chat where users can create a group of any type (public, password-protected, or private), add and remove members with role-based permissions, join or leave a group, transfer ownership, and exchange messages in real time using the CometChat components.

## Prerequisites

* Completed the [Integration Guide](/ui-kit/react/integration-react) guide
* A running `CometChatProvider` setup with valid credentials
* Familiarity with the [Conversations](/ui-kit/react/components/conversations) and [Message List](/ui-kit/react/components/message-list) components

## Components Used

| Component / API                                    | Purpose                                                                |
| :------------------------------------------------- | :--------------------------------------------------------------------- |
| `CometChatConversations`                           | Lists existing conversations including groups                          |
| `CometChatGroupMembers`                            | Built-in member list with role-gated kick / ban / scope-change actions |
| `CometChatMessageHeader`                           | Displays group name, avatar, and member count                          |
| `CometChatMessageList`                             | Renders group messages in real time                                    |
| `CometChatMessageComposer`                         | Text input for sending messages to the group                           |
| `CometChat.createGroup()`                          | SDK method to create a new group                                       |
| `CometChat.joinGroup()`                            | SDK method to join a public or password-protected group                |
| `CometChat.addMembersToGroup()`                    | SDK method to add members                                              |
| `CometChat.kickGroupMember()` / `banGroupMember()` | SDK methods to remove or ban a member                                  |
| `CometChat.updateGroupMemberScope()`               | SDK method to change a member's role                                   |
| `CometChat.leaveGroup()`                           | SDK method to leave a group                                            |
| `CometChat.transferGroupOwnership()`               | SDK method to hand ownership to another member                         |

## Step 1: Set up the app shell

Wrap your application in `CometChatProvider` and create a layout with a sidebar for conversations and a main area for messages.

```tsx App.tsx theme={null}
import { useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import { CometChatProvider } from "@cometchat/chat-uikit-react";
import { GroupChat } from "./GroupChat";

function App() {
  return (
    <CometChatProvider>
      <GroupChat />
    </CometChatProvider>
  );
}

export default App;
```

## Step 2: Create a group

A group has one of three types, and the type decides how other users can get in. Choose the right one up front — it changes both the create call and how (or whether) users can join.

| Type                   | Constant                        | How users get in                                                                                 |
| ---------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------ |
| **Public**             | `CometChat.GROUP_TYPE.PUBLIC`   | Anyone can join, no password.                                                                    |
| **Password-protected** | `CometChat.GROUP_TYPE.PASSWORD` | Users must supply the correct password to join.                                                  |
| **Private**            | `CometChat.GROUP_TYPE.PRIVATE`  | **Add-only.** Users cannot join — not even with a password. An admin or moderator must add them. |

Create a group with `CometChat.createGroup()`. The `CometChat.Group` constructor takes a **fourth `password` argument** — it is required for password-protected groups and ignored for the other two types.

```tsx theme={null}
async function createGroup(
  name: string,
  type: string,
  password = "" // only used when type is PASSWORD
) {
  const group = new CometChat.Group(
    "group-" + Date.now(), // unique GUID
    name,
    type,                  // PUBLIC | PASSWORD | PRIVATE
    password
  );

  try {
    const createdGroup = await CometChat.createGroup(group);
    console.log("Group created:", createdGroup.getName());
    return createdGroup;
  } catch (error) {
    console.error("Group creation failed:", error);
  }
}
```

<Warning>
  For a password-protected group you **must** pass the password as the fourth argument. `new CometChat.Group(guid, name, CometChat.GROUP_TYPE.PASSWORD)` with no password creates a group nobody can join.
</Warning>

<Note>
  When a group is created through the UI Kit's built-in flow, it publishes the `ui:group/created` event on the [Event System](/ui-kit/react/event-system#user--group-actions). Subscribe with `useCometChatEvents` if other components need to react to new groups being created.
</Note>

## Step 3: Add members

The creator becomes the group **owner** (with admin privileges). Add members with `CometChat.addMembersToGroup()` — each member is a `CometChat.GroupMember` with a UID and a scope (`ADMIN`, `MODERATOR`, or `PARTICIPANT`).

```tsx theme={null}
async function addMembers(guid: string, memberUids: string[]) {
  const members = memberUids.map(
    (uid) =>
      new CometChat.GroupMember(uid, CometChat.GROUP_MEMBER_SCOPE.PARTICIPANT)
  );

  try {
    const response = await CometChat.addMembersToGroup(guid, members, []);
    console.log("Members added:", response);
  } catch (error) {
    console.error("Failed to add members:", error);
  }
}
```

<Note>
  Adding members requires an **admin** or **moderator** scope in the target group — a **participant** cannot add members. Assign `PARTICIPANT` by default and only grant `ADMIN`/`MODERATOR` when a member needs management rights. For **private** groups this is the *only* way in — there is no join. To let a user pick who to add, render [`CometChatUsers`](/ui-kit/react/components/users) in selection mode and pass the chosen UIDs to `addMembersToGroup()`.
</Note>

## Step 4: Join a group

How a user joins depends on the group type:

```tsx theme={null}
async function joinGroup(group: CometChat.Group, password = "") {
  const guid = group.getGuid();
  const type = group.getType();

  // Private groups cannot be joined — the user must be added (Step 3).
  if (type === CometChat.GROUP_TYPE.PRIVATE) {
    console.warn("Private groups are add-only; joining is not allowed.");
    return;
  }

  try {
    // Pass the password only for password-protected groups; "" for public.
    const joined = await CometChat.joinGroup(guid, type, password);
    console.log("Joined group:", joined.getName());
    return joined;
  } catch (error) {
    // A wrong password for a PASSWORD group rejects here.
    console.error("Failed to join group:", error);
  }
}
```

<Note>
  Only **public** and **password-protected** groups can be joined. A **private** group is add-only — calling `joinGroup()` on it fails; add the user via [Step 3](#step-3-add-members) instead. The built-in [`CometChatGroups`](/ui-kit/react/components/groups) list surfaces a password prompt for password-protected groups automatically.
</Note>

## Step 5: Manage members — remove, ban, and change roles

The `CometChatGroupMembers` component renders the member list with built-in **kick**, **ban**, and **change-scope** actions. It shows or hides those actions based on the **logged-in user's role**, so you don't have to gate them yourself.

```tsx theme={null}
import { CometChatGroupMembers } from "@cometchat/chat-uikit-react";

function GroupMembersPanel({ group }: { group: CometChat.Group }) {
  return (
    <CometChatGroupMembers
      group={group}
      onBack={() => {/* close the panel */}}
    />
  );
}
```

Group actions are **scope-based** — a participant can never perform them:

| Action                         | Participant |     Moderator     | Admin / Owner |
| ------------------------------ | :---------: | :---------------: | :-----------: |
| Send & receive messages        |      ✅      |         ✅         |       ✅       |
| Add members                    |      ❌      |         ✅         |       ✅       |
| Kick / ban **participants**    |      ❌      |         ✅         |       ✅       |
| Kick / ban admins & moderators |      ❌      |         ❌         |       ✅       |
| Change a member's scope        |      ❌      | participants only |       ✅       |
| Update / delete the group      |      ❌      |    update only    |       ✅       |
| Transfer ownership             |      ❌      |         ❌         |   Owner only  |

If you build your own controls instead of using the component's menu, the SDK methods are:

```tsx theme={null}
// Remove a member from the group
await CometChat.kickGroupMember(guid, uid);

// Ban a member (kicked and blocked from rejoining)
await CometChat.banGroupMember(guid, uid);

// Promote / demote a member
await CometChat.updateGroupMemberScope(
  guid,
  uid,
  CometChat.GROUP_MEMBER_SCOPE.MODERATOR
);
```

<Note>
  Calling these as a participant — or a moderator acting on an admin — rejects with a permission error. Let the acting user's scope drive which controls you render. The component already does this for its default kick/ban/scope menu.
</Note>

## Step 6: Leave a group and transfer ownership

Any member can leave with `CometChat.leaveGroup()` — **except the owner**. An owner must hand ownership to another member with `CometChat.transferGroupOwnership()` *first*; leaving before transferring rejects with an error.

```tsx theme={null}
async function leaveGroup(group: CometChat.Group, loggedInUid: string) {
  const guid = group.getGuid();
  const isOwner = group.getOwner() === loggedInUid;

  try {
    if (isOwner) {
      // Owners cannot leave until ownership is transferred.
      const newOwnerUid = await pickAnotherMember(guid); // your UI: choose a member
      if (!newOwnerUid) return; // no one to hand off to — block the leave
      await CometChat.transferGroupOwnership(guid, newOwnerUid);
    }

    await CometChat.leaveGroup(guid);
    console.log("Left group:", group.getName());
  } catch (error) {
    console.error("Failed to leave group:", error);
  }
}
```

<Warning>
  Wiring "Leave Group" straight to `leaveGroup()` throws for the owner. Detect the owner (`group.getOwner() === loggedInUser.getUid()`), show an **ownership-transfer** step (a member picker — `CometChatGroupMembers` in selection mode works well), call `transferGroupOwnership()`, and only then `leaveGroup()`. See the SDK [Transfer Group Ownership](/sdk/javascript/transfer-group-ownership) and [Leave Group](/sdk/javascript/leave-group) references.
</Warning>

## Step 7: Display conversations and select a group

Use `CometChatConversations` to show the user's conversations. When a group conversation is selected, pass the group object to the message components.

```tsx theme={null}
import { CometChatConversations } from "@cometchat/chat-uikit-react";

function GroupChat() {
  const [activeGroup, setActiveGroup] = useState<CometChat.Group | null>(null);

  function handleConversationClick(conversation: CometChat.Conversation) {
    const entity = conversation.getConversationWith();
    if (entity instanceof CometChat.Group) {
      setActiveGroup(entity);
    }
  }

  return (
    <div style={{ display: "flex", height: "100vh" }}>
      <div style={{ width: "320px", borderRight: "1px solid #e0e0e0" }}>
        <CometChatConversations onItemClick={handleConversationClick} />
      </div>
      <div style={{ flex: 1 }}>
        {activeGroup && <GroupMessageView group={activeGroup} />}
      </div>
    </div>
  );
}
```

## Step 8: Render the group message view

Combine `CometChatMessageList` and `CometChatMessageComposer` to display messages and allow sending within the selected group.

```tsx theme={null}
import {
  CometChatMessageList,
  CometChatMessageComposer,
  CometChatMessageHeader,
} from "@cometchat/chat-uikit-react";

function GroupMessageView({ group }: { group: CometChat.Group }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
      <CometChatMessageHeader group={group} />

      <div style={{ flex: 1, overflow: "hidden" }}>
        <CometChatMessageList group={group} />
      </div>

      <CometChatMessageComposer group={group} />
    </div>
  );
}
```

## Step 9: Add a create-group form

Provide a UI for users to create groups on the fly. Show a password field only when the selected type is password-protected, and pass it through to `createGroup` from Step 2.

```tsx theme={null}
import { useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";

function CreateGroupForm({ onCreate }: { onCreate: (group: CometChat.Group) => void }) {
  const [name, setName] = useState("");
  const [type, setType] = useState<string>(CometChat.GROUP_TYPE.PUBLIC);
  const [password, setPassword] = useState("");

  const isPasswordType = type === CometChat.GROUP_TYPE.PASSWORD;

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (!name.trim()) return;
    if (isPasswordType && !password) return; // password is required for this type

    const group = new CometChat.Group(
      "group-" + Date.now(),
      name.trim(),
      type,
      isPasswordType ? password : ""
    );

    try {
      const createdGroup = await CometChat.createGroup(group);
      onCreate(createdGroup);
      setName("");
      setPassword("");
    } catch (error) {
      console.error("Group creation failed:", error);
    }
  }

  return (
    <form onSubmit={handleSubmit} style={{ padding: "12px" }}>
      <input
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Group name"
        style={{ width: "100%", marginBottom: "8px", padding: "8px" }}
      />
      <select
        value={type}
        onChange={(e) => setType(e.target.value)}
        style={{ width: "100%", marginBottom: "8px", padding: "8px" }}
      >
        <option value={CometChat.GROUP_TYPE.PUBLIC}>Public</option>
        <option value={CometChat.GROUP_TYPE.PRIVATE}>Private (add-only)</option>
        <option value={CometChat.GROUP_TYPE.PASSWORD}>Password Protected</option>
      </select>
      {isPasswordType && (
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          placeholder="Group password"
          style={{ width: "100%", marginBottom: "8px", padding: "8px" }}
        />
      )}
      <button type="submit" style={{ width: "100%", padding: "8px" }}>
        Create Group
      </button>
    </form>
  );
}
```

## Complete Example

<Note>
  The **"New Group"** button lives in the conversation list's `headerView` slot — not in a separate `<div>` stacked above the list — so the list header stays intact and the layout doesn't shift. Because `headerView` replaces the entire default header, re-render the default title (**"Chats"**) alongside the button.
</Note>

```tsx GroupChat.tsx theme={null}
import { useState } from "react";
import { CometChat } from "@cometchat/chat-sdk-javascript";
import {
  CometChatProvider,
  CometChatConversations,
  CometChatMessageList,
  CometChatMessageComposer,
  CometChatMessageHeader,
} from "@cometchat/chat-uikit-react";

function CreateGroupForm({ onCreate }: { onCreate: (group: CometChat.Group) => void }) {
  const [name, setName] = useState("");
  const [type, setType] = useState<string>(CometChat.GROUP_TYPE.PUBLIC);
  const [password, setPassword] = useState("");

  const isPasswordType = type === CometChat.GROUP_TYPE.PASSWORD;

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (!name.trim()) return;
    if (isPasswordType && !password) return;

    const group = new CometChat.Group(
      "group-" + Date.now(),
      name.trim(),
      type,
      isPasswordType ? password : ""
    );

    try {
      const createdGroup = await CometChat.createGroup(group);
      onCreate(createdGroup);
      setName("");
      setPassword("");
    } catch (error) {
      console.error("Group creation failed:", error);
    }
  }

  return (
    <form onSubmit={handleSubmit} style={{ padding: "12px" }}>
      <input
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Group name"
        style={{ width: "100%", marginBottom: "8px", padding: "8px" }}
      />
      <select
        value={type}
        onChange={(e) => setType(e.target.value)}
        style={{ width: "100%", marginBottom: "8px", padding: "8px" }}
      >
        <option value={CometChat.GROUP_TYPE.PUBLIC}>Public</option>
        <option value={CometChat.GROUP_TYPE.PRIVATE}>Private (add-only)</option>
        <option value={CometChat.GROUP_TYPE.PASSWORD}>Password Protected</option>
      </select>
      {isPasswordType && (
        <input
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          placeholder="Group password"
          style={{ width: "100%", marginBottom: "8px", padding: "8px" }}
        />
      )}
      <button type="submit" style={{ width: "100%", padding: "8px" }}>
        Create Group
      </button>
    </form>
  );
}

function GroupMessageView({ group }: { group: CometChat.Group }) {
  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
      <CometChatMessageHeader group={group} />

      <div style={{ flex: 1, overflow: "hidden" }}>
        <CometChatMessageList group={group} />
      </div>

      <CometChatMessageComposer group={group} />
    </div>
  );
}

function GroupChat() {
  const [activeGroup, setActiveGroup] = useState<CometChat.Group | null>(null);
  const [showCreateForm, setShowCreateForm] = useState(false);

  function handleConversationClick(conversation: CometChat.Conversation) {
    const entity = conversation.getConversationWith();
    if (entity instanceof CometChat.Group) {
      setActiveGroup(entity);
    }
  }

  function handleGroupCreated(group: CometChat.Group) {
    setActiveGroup(group);
    setShowCreateForm(false);
  }

  return (
    <div style={{ display: "flex", height: "100vh" }}>
      <div style={{ width: "320px", borderRight: "1px solid #e0e0e0", display: "flex", flexDirection: "column" }}>
        {showCreateForm && <CreateGroupForm onCreate={handleGroupCreated} />}

        <div style={{ flex: 1, overflow: "hidden" }}>
          <CometChatConversations
            onItemClick={handleConversationClick}
            headerView={
              // headerView replaces the whole default header, so re-render the "Chats" title next to the button
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 16px" }}>
                <span style={{ fontWeight: "bold" }}>Chats</span>
                <button onClick={() => setShowCreateForm(!showCreateForm)}>
                  {showCreateForm ? "Cancel" : "New Group"}
                </button>
              </div>
            }
          />
        </div>
      </div>

      <div style={{ flex: 1 }}>
        {activeGroup ? (
          <GroupMessageView group={activeGroup} />
        ) : (
          <div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%" }}>
            <p>Select a group conversation or create a new group</p>
          </div>
        )}
      </div>
    </div>
  );
}

function App() {
  return (
    <CometChatProvider>
      <GroupChat />
    </CometChatProvider>
  );
}

export default App;
```

## Next Steps

* [Groups](/ui-kit/react/components/groups) — browse and join existing groups
* [Group Members](/ui-kit/react/components/group-members) — manage group membership with role-based actions
* [Kick / Ban Members](/sdk/javascript/group-kick-ban-members) · [Change Member Scope](/sdk/javascript/group-change-member-scope) · [Transfer Ownership](/sdk/javascript/transfer-group-ownership) — SDK references
* [Message Header](/ui-kit/react/components/message-header) — customize the group header
* [Event System](/ui-kit/react/event-system#user--group-actions) — react to `ui:group/created` and other group action events
* [CometChatProvider](/ui-kit/react/cometchat-provider) — configure the root provider
