Overview
The CometChatGroups component displays a real-time, scrollable list of groups with support for search, selection modes, and extensive customization. It provides an integral search functionality, allowing you to locate any specific group swiftly and easily. For each group listed, the component displays the group’s name by default, in conjunction with their avatar when available. Furthermore, it includes a group type indicator (public, private, or password-protected) and member count.
The component follows a Manager-based Architecture where:
GroupsManager handles SDK request building and pagination
Component manages state, real-time listeners, and UI rendering
Templates allow extensive customization of all UI sections
Key Features
Real-time Updates : Automatic updates for group member events (join, leave, kick, ban)
Flexible Customization : Extensive template projection for all UI sections
Selection Modes : Support for single and multiple group selection
Group Type Indicators : Visual indicators for public, private, and password-protected groups
Search Functionality : Built-in search with 300ms debouncing
Keyboard Navigation : Full keyboard accessibility with arrow keys and shortcuts (WCAG 2.1 Level AA compliant)
Context Menu : Customizable actions for each group
Error Handling : Comprehensive error handling with custom error views
Keyboard Accessibility
CometChatGroups is fully keyboard accessible and meets WCAG 2.1 Level AA standards. All functionality can be accessed using only the keyboard.
Keyboard Shortcuts
Key Action Context TabNavigate between UI elements Global Shift + TabNavigate backwards Global ↓ (Down Arrow)Focus next group When list is focused ↑ (Up Arrow)Focus previous group When list is focused EnterSelect/activate focused group When group is focused SpaceToggle selection (in multiple mode) When group is focused EscapeClear search and reset focus When list is focused
Accessibility Features
ARIA Attributes:
role="list" on groups container
role="listitem" on each group item
aria-label with group name, type, and member count
aria-selected indicates selected groups
Proper tabindex management (roving tabindex pattern)
Screen Reader Support:
Announces group details when focused
Announces selection state changes
Announces group type (public/private/password)
Semantic HTML structure
Focus Management:
Visible focus indicators (2px border) meeting WCAG contrast requirements
Focus restoration after interactions
Roving tabindex for efficient keyboard navigation
WCAG 2.1 Compliance:
✅ 2.1.1 Keyboard (Level A) - All functionality available via keyboard
✅ 2.1.2 No Keyboard Trap (Level A) - Users can navigate away using keyboard
✅ 2.4.3 Focus Order (Level A) - Logical focus order
✅ 2.4.7 Focus Visible (Level AA) - Visible focus indicators
✅ 4.1.2 Name, Role, Value (Level A) - Proper ARIA attributes
Basic Usage
Simple Implementation
import { Component } from '@angular/core' ;
import { CometChatGroupsComponent } from '@cometchat/chat-uikit-angular' ;
@ Component ({
selector: 'app-groups' ,
standalone: true ,
imports: [ CometChatGroupsComponent ],
template: `
<cometchat-groups
(itemClick)="onGroupClick($event)"
></cometchat-groups>
`
})
export class GroupsComponent {
onGroupClick ( group : any ) : void {
console . log ( 'Selected group:' , group );
// Navigate to messages view or handle group selection
}
}
See all 19 lines
With Search and Group Type Indicators
< cometchat - groups
[ hideSearch ] = "false"
[ hideGroupType ] = "false"
( itemClick ) = "onGroupClick($event)"
( error ) = "onError($event)"
> </ cometchat - groups >
Properties
Display Control Properties
Property Type Default Description hideSearchbooleanfalseHide the search bar hideErrorbooleanfalseHide error views when errors occur hideGroupTypebooleanfalseHide group type icon (public/private/password) showScrollbarbooleanfalseShow/hide scrollbar in group list disableDefaultContextMenubooleantrueWhen true, prevents the browser’s native context menu and shows the custom context menu instead
Data Configuration Properties
Property Type Default Description groupsRequestBuilderCometChat.GroupsRequestBuilderundefinedCustom request builder for filtering and pagination searchRequestBuilderCometChat.GroupsRequestBuilderundefinedCustom request builder specifically for search queries activeGroupCometChat.GroupundefinedCurrently active/highlighted group selectionModeSelectionMode'none'Selection mode: 'none', 'single', or 'multiple'
Customization Properties
Property Type Default Description options(group: CometChat.Group) => CometChatOption[]undefinedFunction to provide custom context menu options
Template Properties
Property Type Default Description headerViewTemplateRef<any>undefinedCustom template for entire header section menuViewTemplateRef<any>undefinedCustom template for menu area in the header (e.g., action buttons, 3-dot menu) loadingViewTemplateRef<any>undefinedCustom template for loading state emptyViewTemplateRef<any>undefinedCustom template for empty state errorViewTemplateRef<any>undefinedCustom template for error state itemViewTemplateRef<{$implicit: CometChat.Group}>undefinedCustom template for entire group item leadingViewTemplateRef<{$implicit: CometChat.Group}>undefinedCustom template for leading section (avatar area) titleViewTemplateRef<{$implicit: CometChat.Group}>undefinedCustom template for title section subtitleViewTemplateRef<{$implicit: CometChat.Group}>undefinedCustom template for subtitle section trailingViewTemplateRef<{$implicit: CometChat.Group}>undefinedCustom template for trailing section (selection controls)
Events
Event Payload Type Description itemClickCometChat.GroupEmitted when a group item is clicked select{group: CometChat.Group, selected: boolean}Emitted when a group is selected/deselected errorCometChat.CometChatExceptionEmitted when an error occurs selectionChangeSelectionStateEmitted when the selection state changes in selection mode
Usage Patterns
CometChatGroups supports two usage patterns for communicating the selected group to downstream components.
Using Service
Using Props
When a group is selected, ChatStateService stores the active group. Downstream components like cometchat-message-header, cometchat-message-list, and cometchat-message-composer automatically subscribe to the change. import { Component } from '@angular/core' ;
import {
CometChatGroupsComponent ,
CometChatMessageHeaderComponent ,
CometChatMessageListComponent ,
CometChatMessageComposerComponent ,
} from '@cometchat/chat-uikit-angular' ;
@ Component ({
selector: 'app-groups-chat' ,
standalone: true ,
imports: [
CometChatGroupsComponent ,
CometChatMessageHeaderComponent ,
CometChatMessageListComponent ,
CometChatMessageComposerComponent ,
],
template: `
<div class="chat-layout">
<cometchat-groups
(itemClick)="onGroupClick($event)"
></cometchat-groups>
<div class="chat-panel">
<!-- Auto-subscribe to ChatStateService active group -->
<cometchat-message-header></cometchat-message-header>
<cometchat-message-list></cometchat-message-list>
<cometchat-message-composer></cometchat-message-composer>
</div>
</div>
` ,
})
export class GroupsChatComponent {
onGroupClick ( group : any ) : void {
// ChatStateService is updated automatically
}
}
See all 37 lines
This is the recommended approach. Selecting a group automatically updates all downstream message components.
Pass [group] directly to downstream components to override ChatStateService state. This is useful when you manage group selection yourself. import { Component } from '@angular/core' ;
import { CometChat } from '@cometchat/chat-sdk-javascript' ;
import {
CometChatGroupsComponent ,
CometChatMessageHeaderComponent ,
CometChatMessageListComponent ,
CometChatMessageComposerComponent ,
} from '@cometchat/chat-uikit-angular' ;
@ Component ({
selector: 'app-groups-chat' ,
standalone: true ,
imports: [
CometChatGroupsComponent ,
CometChatMessageHeaderComponent ,
CometChatMessageListComponent ,
CometChatMessageComposerComponent ,
],
template: `
<div class="chat-layout">
<cometchat-groups
(itemClick)="onGroupClick($event)"
></cometchat-groups>
@if (activeGroup) {
<div class="chat-panel">
<cometchat-message-header [group]="activeGroup"></cometchat-message-header>
<cometchat-message-list [group]="activeGroup"></cometchat-message-list>
<cometchat-message-composer [group]="activeGroup"></cometchat-message-composer>
</div>
}
</div>
` ,
})
export class GroupsChatComponent {
activeGroup : CometChat . Group | null = null ;
onGroupClick ( group : CometChat . Group ) : void {
this . activeGroup = group ;
}
}
See all 41 lines
When [group] inputs are provided, they take priority over ChatStateService state for that component instance.
Advanced Usage
Filtering Groups with Request Builder
Use the groupsRequestBuilder to filter groups by various criteria:
import { Component , OnInit } from '@angular/core' ;
import { CometChat } from '@cometchat/chat-sdk-javascript' ;
import { CometChatGroupsComponent } from '@cometchat/chat-uikit-angular' ;
@ Component ({
selector: 'app-filtered-groups' ,
standalone: true ,
imports: [ CometChatGroupsComponent ],
template: `
<cometchat-groups
[groupsRequestBuilder]="groupsBuilder"
(itemClick)="onGroupClick($event)"
></cometchat-groups>
`
})
export class FilteredGroupsComponent implements OnInit {
groupsBuilder !: CometChat . GroupsRequestBuilder ;
ngOnInit () : void {
// Show only joined groups with limit of 20
this . groupsBuilder = new CometChat . GroupsRequestBuilder ()
. setLimit ( 20 )
. joinedOnly ( true );
}
onGroupClick ( group : CometChat . Group ) : void {
console . log ( 'Group clicked:' , group );
}
}
See all 29 lines
GroupsRequestBuilder Methods
Method Type Description setLimitnumberSets the number of groups fetched per request (pagination) setSearchKeywordstringFetches groups matching the search string joinedOnlybooleanFetches only groups the logged-in user has joined setTagsstring[]Fetches groups with specified tags withTagsbooleanIncludes tag information in response setGUIDsstring[]Fetches specific groups by GUIDs
Selection Modes
Enable single or multiple group selection:
import { Component } from '@angular/core' ;
import { CometChat } from '@cometchat/chat-sdk-javascript' ;
import { CometChatGroupsComponent , SelectionMode } from '@cometchat/chat-uikit-angular' ;
@ Component ({
selector: 'app-selectable-groups' ,
standalone: true ,
imports: [ CometChatGroupsComponent ],
template: `
<div class="group-selection">
@if (selectedGroups.length > 0) {
<div class="toolbar">
<span>{{ selectedGroups.length }} groups selected</span>
<button (click)="performAction()">Perform Action</button>
</div>
}
<cometchat-groups
[selectionMode]="selectionMode"
(select)="onGroupSelect($event)"
(itemClick)="onGroupClick($event)"
></cometchat-groups>
</div>
`
})
export class SelectableGroupsComponent {
selectionMode = SelectionMode . multiple ;
selectedGroups : CometChat . Group [] = [];
onGroupSelect ( event : { group : CometChat . Group ; selected : boolean }) : void {
if ( event . selected ) {
this . selectedGroups . push ( event . group );
} else {
this . selectedGroups = this . selectedGroups . filter (
g => g . getGuid () !== event . group . getGuid ()
);
}
}
onGroupClick ( group : CometChat . Group ) : void {
console . log ( 'Group clicked:' , group );
}
performAction () : void {
console . log ( 'Performing action on groups:' , this . selectedGroups );
}
}
See all 47 lines
Provide custom actions for each group:
import { Component } from '@angular/core' ;
import { CometChat } from '@cometchat/chat-sdk-javascript' ;
import { CometChatGroupsComponent , CometChatOption } from '@cometchat/chat-uikit-angular' ;
@ Component ({
selector: 'app-custom-menu-groups' ,
standalone: true ,
imports: [ CometChatGroupsComponent ],
template: `
<cometchat-groups
[options]="getCustomOptions"
(itemClick)="onGroupClick($event)"
></cometchat-groups>
`
})
export class CustomMenuGroupsComponent {
getCustomOptions = ( group : CometChat . Group ) : CometChatOption [] => {
return [
{
id: 'open' ,
title: 'Open Group' ,
iconURL: 'assets/chat-icon.svg' ,
onClick : () => this . openGroup ( group )
},
{
id: 'members' ,
title: 'View Members' ,
iconURL: 'assets/members-icon.svg' ,
onClick : () => this . viewMembers ( group )
},
{
id: 'leave' ,
title: 'Leave Group' ,
iconURL: 'assets/leave-icon.svg' ,
onClick : () => this . leaveGroup ( group )
}
];
};
openGroup ( group : CometChat . Group ) : void {
console . log ( 'Opening group:' , group . getName ());
}
viewMembers ( group : CometChat . Group ) : void {
console . log ( 'Viewing members of:' , group . getName ());
}
leaveGroup ( group : CometChat . Group ) : void {
console . log ( 'Leaving group:' , group . getName ());
}
onGroupClick ( group : CometChat . Group ) : void {
console . log ( 'Group clicked:' , group );
}
}
See all 55 lines
Customization with Templates
Custom Subtitle View
Customize the subtitle section to show member count and group type:
import { Component } from '@angular/core' ;
import { CommonModule } from '@angular/common' ;
import { CometChat } from '@cometchat/chat-sdk-javascript' ;
import { CometChatGroupsComponent } from '@cometchat/chat-uikit-angular' ;
@ Component ({
selector: 'app-custom-subtitle' ,
standalone: true ,
imports: [ CommonModule , CometChatGroupsComponent ],
template: `
<cometchat-groups
[subtitleView]="customSubtitle"
(itemClick)="onGroupClick($event)"
>
<ng-template #customSubtitle let-group>
<div class="custom-subtitle">
<span class="members">
👥 {{ group.getMembersCount() }} members
</span>
<span class="type" [class]="group.getType()">
{{ getGroupTypeLabel(group) }}
</span>
</div>
</ng-template>
</cometchat-groups>
` ,
styles: [ `
.custom-subtitle {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
}
.members {
color: #666;
}
.type {
padding: 2px 6px;
border-radius: 4px;
font-size: 10px;
font-weight: 500;
}
.type.public { background: #E8F5E9; color: #4CAF50; }
.type.private { background: #FFF3E0; color: #FF9800; }
.type.password { background: #FFEBEE; color: #F44336; }
` ]
})
export class CustomSubtitleComponent {
getGroupTypeLabel ( group : CometChat . Group ) : string {
const type = group . getType ();
switch ( type ) {
case CometChat . GROUP_TYPE . PUBLIC : return '🌐 Public' ;
case CometChat . GROUP_TYPE . PRIVATE : return '🔒 Private' ;
case CometChat . GROUP_TYPE . PASSWORD : return '🔑 Password' ;
default : return type ;
}
}
onGroupClick ( group : CometChat . Group ) : void {
console . log ( 'Group clicked:' , group );
}
}
See all 62 lines
Custom Empty and Error States
Provide custom views for empty and error states:
import { Component } from '@angular/core' ;
import { CommonModule } from '@angular/common' ;
import { CometChatGroupsComponent } from '@cometchat/chat-uikit-angular' ;
@ Component ({
selector: 'app-custom-states' ,
standalone: true ,
imports: [ CommonModule , CometChatGroupsComponent ],
template: `
<cometchat-groups
[emptyView]="customEmpty"
[errorView]="customError"
(itemClick)="onGroupClick($event)"
(error)="onError($event)"
>
<ng-template #customEmpty>
<div class="custom-empty-state">
<img src="assets/no-groups.svg" alt="No groups" />
<h3>No Groups Found</h3>
<p>Create a new group or join an existing one</p>
<button (click)="createGroup()">Create Group</button>
</div>
</ng-template>
<ng-template #customError>
<div class="custom-error-state">
<img src="assets/error-icon.svg" alt="Error" />
<h3>Something went wrong</h3>
<p>We couldn't load the groups list</p>
<button (click)="retryLoading()">Try Again</button>
</div>
</ng-template>
</cometchat-groups>
`
})
export class CustomStatesComponent {
createGroup () : void {
console . log ( 'Creating new group' );
}
retryLoading () : void {
console . log ( 'Retrying to load groups' );
}
onGroupClick ( group : any ) : void {
console . log ( 'Group clicked:' , group );
}
onError ( error : any ) : void {
console . error ( 'Error:' , error );
}
}
See all 52 lines
Styling with CSS Variables
The CometChatGroups component uses CSS variables for comprehensive theming:
cometchat-groups {
/* Background colors */
--cometchat-background-color-01 : #ffffff ;
--cometchat-background-color-02 : #f5f5f5 ;
--cometchat-background-color-03 : #e8e8e8 ;
/* Text colors */
--cometchat-text-color-primary : #141414 ;
--cometchat-text-color-secondary : #727272 ;
/* Border colors */
--cometchat-border-color-light : #e8e8e8 ;
/* Primary color */
--cometchat-primary-color : #6852D6 ;
/* Typography */
--cometchat-font-heading2-bold : 700 20 px / 24 px Roboto;
--cometchat-font-body-regular : 400 14 px / 16.8 px Roboto;
--cometchat-font-caption1-medium : 500 12 px / 14.4 px Roboto;
/* Spacing */
--cometchat-spacing-1 : 4 px ;
--cometchat-spacing-2 : 8 px ;
--cometchat-spacing-3 : 12 px ;
--cometchat-spacing-4 : 16 px ;
/* Border radius */
--cometchat-radius-2 : 8 px ;
--cometchat-radius-max : 1000 px ;
}
See all 31 lines
Dark Theme Example
.dark-theme cometchat-groups {
--cometchat-background-color-01 : #1a1a1a ;
--cometchat-background-color-02 : #2a2a2a ;
--cometchat-background-color-03 : #333333 ;
--cometchat-text-color-primary : #ffffff ;
--cometchat-text-color-secondary : #cccccc ;
--cometchat-border-color-light : #444444 ;
}
Real-Time Features
Automatic Updates
The component automatically updates in real-time for:
Member Events : Join, leave, kick, ban events are reflected immediately
Group Updates : Name, icon, and description changes
Connection Recovery : Automatically refreshes the list when connection is re-established
Event Subscriptions
The component subscribes to the following events:
// SDK GroupListener events
CometChat . GroupListener . onGroupMemberJoined ( action , joinedUser , joinedGroup )
CometChat . GroupListener . onGroupMemberLeft ( action , leftUser , leftGroup )
CometChat . GroupListener . onGroupMemberKicked ( action , kickedUser , kickedBy , kickedFrom )
CometChat . GroupListener . onGroupMemberBanned ( action , bannedUser , bannedBy , bannedFrom )
CometChat . GroupListener . onMemberAddedToGroup ( action , addedBy , addedUser , addedTo )
// CometChatGroupEvents
CometChatGroupEvents . ccGroupCreated
CometChatGroupEvents . ccGroupDeleted
CometChatGroupEvents . ccGroupLeft
CometChatGroupEvents . ccGroupMemberAdded
// Connection events
CometChat . ConnectionListener . onConnected ()
See all 15 lines
Error Handling
Built-in Error Handling
The component includes comprehensive error handling:
< cometchat - groups
[ hideError ] = "false"
( error ) = "handleError($event)"
( itemClick ) = "onGroupClick($event)"
> </ cometchat - groups >
handleError ( error : CometChat . CometChatException ): void {
console . error ( 'Groups error:' , error );
if ( error . code === 'NETWORK_ERROR' ) {
this . showToast ( 'Network error. Please check your connection.' );
} else if ( error . code === 'AUTH_ERROR' ) {
this . showToast ( 'Authentication error. Please log in again.' );
} else {
this . showToast ( 'An error occurred. Please try again.' );
}
}
See all 11 lines
Best Practices
Use groupsRequestBuilder to limit the initial fetch size for better performance. The default limit is 30 groups per page.
Always handle the error event to provide feedback to users when something goes wrong.
The component uses OnPush change detection strategy for optimal performance. If you’re using custom templates with external state, ensure proper change detection triggering.
Use hideGroupType to simplify the UI if your application only uses one type of group.
When using custom context menu options, ensure the onClick handlers are properly bound to avoid this context issues. Use arrow functions.
Complete Example
Here’s a comprehensive example combining multiple features:
import { Component , OnInit , OnDestroy } from '@angular/core' ;
import { CommonModule } from '@angular/common' ;
import { CometChat } from '@cometchat/chat-sdk-javascript' ;
import {
CometChatGroupsComponent ,
SelectionMode ,
CometChatOption
} from '@cometchat/chat-uikit-angular' ;
import { Subject , takeUntil } from 'rxjs' ;
@ Component ({
selector: 'app-groups-demo' ,
standalone: true ,
imports: [ CommonModule , CometChatGroupsComponent ],
template: `
<div class="groups-container">
@if (selectedGroups.length > 0) {
<div class="toolbar">
<span>{{ selectedGroups.length }} selected</span>
<button (click)="clearSelection()">Clear</button>
</div>
}
<cometchat-groups
[groupsRequestBuilder]="groupsBuilder"
[selectionMode]="selectionMode"
[options]="getCustomOptions"
[subtitleView]="customSubtitle"
(itemClick)="onGroupClick($event)"
(select)="onGroupSelect($event)"
(error)="handleError($event)"
(empty)="handleEmpty()"
>
<ng-template #customSubtitle let-group>
<div class="group-subtitle">
<span>{{ group.getMembersCount() }} members</span>
<span class="type">{{ getGroupTypeLabel(group) }}</span>
</div>
</ng-template>
</cometchat-groups>
</div>
` ,
styles: [ `
.groups-container {
height: 100vh;
display: flex;
flex-direction: column;
}
.toolbar {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
background-color: #f5f5f5;
border-bottom: 1px solid #e8e8e8;
}
.group-subtitle {
display: flex;
gap: 8px;
font-size: 12px;
color: #666;
}
.type {
color: #6852D6;
}
` ]
})
export class GroupsDemoComponent implements OnInit , OnDestroy {
groupsBuilder !: CometChat . GroupsRequestBuilder ;
selectionMode = SelectionMode . multiple ;
selectedGroups : CometChat . Group [] = [];
private destroy$ = new Subject < void >();
ngOnInit () : void {
this . groupsBuilder = new CometChat . GroupsRequestBuilder ()
. setLimit ( 30 )
. joinedOnly ( true );
}
ngOnDestroy () : void {
this . destroy$ . next ();
this . destroy$ . complete ();
}
getCustomOptions = ( group : CometChat . Group ) : CometChatOption [] => {
return [
{
id: 'open' ,
title: 'Open' ,
iconURL: 'assets/chat.svg' ,
onClick : () => this . openGroup ( group )
},
{
id: 'leave' ,
title: 'Leave' ,
iconURL: 'assets/leave.svg' ,
onClick : () => this . leaveGroup ( group )
}
];
};
getGroupTypeLabel ( group : CometChat . Group ) : string {
const type = group . getType ();
switch ( type ) {
case CometChat . GROUP_TYPE . PUBLIC : return 'Public' ;
case CometChat . GROUP_TYPE . PRIVATE : return 'Private' ;
case CometChat . GROUP_TYPE . PASSWORD : return 'Password' ;
default : return type ;
}
}
onGroupClick ( group : CometChat . Group ) : void {
console . log ( 'Group clicked:' , group . getName ());
}
onGroupSelect ( event : { group : CometChat . Group ; selected : boolean }) : void {
if ( event . selected ) {
this . selectedGroups . push ( event . group );
} else {
this . selectedGroups = this . selectedGroups . filter (
g => g . getGuid () !== event . group . getGuid ()
);
}
}
openGroup ( group : CometChat . Group ) : void {
console . log ( 'Opening group:' , group . getName ());
}
leaveGroup ( group : CometChat . Group ) : void {
console . log ( 'Leaving group:' , group . getName ());
}
clearSelection () : void {
this . selectedGroups = [];
}
handleError ( error : CometChat . CometChatException ) : void {
console . error ( 'Error:' , error );
}
handleEmpty () : void {
console . log ( 'No groups found' );
}
}
See all 146 lines