Skip to main content

Overview

The CometChat Angular UIKit uses a Hybrid Approach for managing active chat state. At its core, ChatStateService acts as a single source of truth for the currently active chat entity — a CometChat.User, CometChat.Group, or CometChat.Conversation. The Hybrid Approach gives you two ways to wire components:
  1. Service-based (default) — Components automatically subscribe to ChatStateService and react when the active entity changes. No prop passing required.
  2. Props override — Pass [user] or [group] via @Input() bindings to override the service state for a specific component instance.
This design exists because most applications need a simple, zero-config wiring mechanism (service-based), while advanced use cases — like multi-panel layouts or isolated chat windows — require explicit control (props-based). The Hybrid Approach delivers both without forcing a choice upfront. ChatStateService is provided at the root level (providedIn: 'root') and exposes both Angular Signals and RxJS Observables, so you can choose whichever reactive API fits your codebase.

Decision Matrix

Use this table to decide which pattern fits your use case:
Start with the service-based pattern. It covers the majority of use cases with zero boilerplate. Switch to props-based only when you need independent state per component instance.

Service-Based Pattern

With the service-based pattern, you place Chat-Aware Components in your template and they automatically subscribe to ChatStateService. When a user selects a conversation, the service updates and all downstream components react — no explicit binding needed.
In this example:
  • <cometchat-conversations> calls ChatStateService.setActiveConversation() when a conversation is clicked
  • setActiveConversation() extracts the CometChat.User or CometChat.Group from the conversation and sets it as the active entity
  • <cometchat-message-header>, <cometchat-message-list>, and <cometchat-message-composer> automatically subscribe to the active user/group and update their UI
This is the recommended approach for most applications. It reduces boilerplate and keeps components in sync automatically. You don’t need to handle (itemClick) events or pass data between components — ChatStateService handles the wiring.

Props-Based Pattern

With the props-based pattern, you manage state yourself and pass [user] or [group] directly to each component via @Input() bindings. This gives you full control over which entity each component displays.
When [user] or [group] @Input() bindings are provided, they take priority over ChatStateService state for that component instance. Other component instances without explicit bindings continue to read from the service.

Mutual Exclusivity

ChatStateService enforces that only one chat entity — a CometChat.User or a CometChat.Group — can be active at any given time:
  • Calling setActiveUser(user) with a non-null value automatically sets activeGroup to null
  • Calling setActiveGroup(group) with a non-null value automatically sets activeUser to null
  • Calling setActiveConversation(conversation) extracts the entity and delegates to setActiveUser() or setActiveGroup(), applying the same rule
  • Calling clearActiveChat() resets all state to null
This prevents ambiguous states where both a user and a group appear active simultaneously.
Setting a user clears the group, and setting a group clears the user. You do not need to manually clear the previous entity before setting a new one — ChatStateService handles this automatically.

Advanced Patterns

Multi-Panel Chat Layouts

For applications that display multiple chat panels side by side (e.g., a support dashboard), use the props-based pattern to give each panel its own independent state:
Each panel receives its own [user] or [group] binding, so they operate independently of ChatStateService. This avoids the mutual exclusivity constraint that applies to service-based state.

Programmatic Navigation

Use ChatStateService to programmatically switch the active chat — for example, when navigating from a notification or deep link:

Cleanup via clearActiveChat()

Call clearActiveChat() to reset all active state when the user logs out, navigates away from the chat interface, or closes a chat window:
Always call clearActiveChat() during logout to ensure no stale state persists across sessions.

Scoping Customization Services for Multiple Instances

The sections above cover ChatStateService and how to use props to give each panel its own data. But there’s a related concern: customization services like MessageBubbleConfigService and FormatterConfigService are also root-level singletons. If you configure custom bubble templates or formatters globally, those customizations apply to every message list in the app. When you need different customizations per panel (e.g., a main chat with full bubble styling and a thread panel with minimal styling), use Angular’s hierarchical dependency injection to scope the service:
The main panel’s customizations (set on the root singleton) do not affect the thread panel, and vice versa. Services you can scope this way:
Do not scope ChatStateService. It is intentionally a singleton that tracks the app-wide active conversation. Scoping it would break cross-component state synchronization. Use the props-based pattern instead for independent panels.
See CometChatMessageList — Multiple Message Lists with Different Configurations for a complete example with two panels.