From 0cb319b4bb95d0cf39a024272d7332244d85eafb Mon Sep 17 00:00:00 2001 From: shagun-cometchat Date: Wed, 3 Jun 2026 19:02:35 +0530 Subject: [PATCH 1/2] add component view customization examples --- ui-kit/react/components/ai-assistant-chat.mdx | 144 ++++- ui-kit/react/components/call-logs.mdx | 2 - ui-kit/react/components/conversations.mdx | 573 ++++++++++++++++-- ui-kit/react/components/group-members.mdx | 305 +++++++++- ui-kit/react/components/groups.mdx | 209 ++++++- ui-kit/react/components/incoming-call.mdx | 78 ++- ui-kit/react/components/message-composer.mdx | 74 ++- ui-kit/react/components/message-header.mdx | 150 ++++- ui-kit/react/components/message-list.mdx | 117 +++- ui-kit/react/components/outgoing-call.mdx | 128 +++- ui-kit/react/components/search.mdx | 210 ++++++- ui-kit/react/components/thread-header.mdx | 18 +- ui-kit/react/components/users.mdx | 260 +++++++- 13 files changed, 2205 insertions(+), 63 deletions(-) diff --git a/ui-kit/react/components/ai-assistant-chat.mdx b/ui-kit/react/components/ai-assistant-chat.mdx index b0c911b54..7be250930 100644 --- a/ui-kit/react/components/ai-assistant-chat.mdx +++ b/ui-kit/react/components/ai-assistant-chat.mdx @@ -288,7 +288,149 @@ Use view props to replace sections of the default UI while keeping the component | `headerTrailingView` | `ReactNode` | Header trailing section | | `headerAuxiliaryButtonView` | `ReactNode` | Header auxiliary buttons (New Chat + History) | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the AI assistant chat */} +#### emptyChatImageView + + + + + +```tsx +import { useState, useEffect } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatAIAssistantChat } from "@cometchat/chat-uikit-react"; + +function AIAssistantCustomImage() { + const [agent, setAgent] = useState(); + + useEffect(() => { + CometChat.getUser("assistant_uid").then((u) => setAgent(u)); + }, []); + + if (!agent) return null; + + return ( + } + /> + ); +} +``` + +#### emptyChatGreetingView + + + + + + + +```tsx +import { useState, useEffect } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatAIAssistantChat } from "@cometchat/chat-uikit-react"; + +function AIAssistantCustomGreeting() { + const [agent, setAgent] = useState(); + + useEffect(() => { + CometChat.getUser("assistant_uid").then((u) => setAgent(u)); + }, []); + + if (!agent) return null; + + return ( + + Free Plan . + Upgrade + + } + /> + ); +} +``` + + +```css +.cometchat-ai-assistant-chat__empty-chat-greeting { + display: flex; + padding: 8px 20px; + justify-content: center; + align-items: center; + gap: 8px; + border-radius: 6px; + border: 1px solid #e8e8e8; + background: #f5f5f5; + width: fit-content; + align-self: center; +} + +.cometchat-ai-assistant-chat__empty-chat-greeting .upgrade-button { + color: #6852d6; +} +``` + + + +#### emptyChatIntroMessageView + + + + + + + +```tsx +import { useState, useEffect } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatAIAssistantChat } from "@cometchat/chat-uikit-react"; + +function AIAssistantCustomIntro() { + const [agent, setAgent] = useState(); + + useEffect(() => { + CometChat.getUser("assistant_uid").then((u) => setAgent(u)); + }, []); + + if (!agent) return null; + + return ( + + Hey, nice to see you What's new? + + } + /> + ); +} +``` + + +```css +.cometchat-ai-assistant-chat__empty-chat-intro { + display: flex; + padding: 12px; + justify-content: center; + align-items: center; + gap: 10px; + border-radius: 12px; + background: #f9f8fd; + width: 172px; + color: #141414; + text-align: center; + font-size: 16px; + font-weight: 400; + line-height: 140%; + margin: 10px 0; +} +``` + + ### CSS Styling diff --git a/ui-kit/react/components/call-logs.mdx b/ui-kit/react/components/call-logs.mdx index b9cc27448..0fe2e055a 100644 --- a/ui-kit/react/components/call-logs.mdx +++ b/ui-kit/react/components/call-logs.mdx @@ -241,8 +241,6 @@ Use view props to replace sections of the default UI while keeping the component | `emptyView` | `ReactNode` | Empty state | | `errorView` | `ReactNode` | Error state | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the call log item */} - ### CSS Styling Override design tokens on the component selector: diff --git a/ui-kit/react/components/conversations.mdx b/ui-kit/react/components/conversations.mdx index 974e848c7..2dfd3e667 100644 --- a/ui-kit/react/components/conversations.mdx +++ b/ui-kit/react/components/conversations.mdx @@ -77,8 +77,7 @@ description: "Scrollable list of recent one-on-one and group conversations for t "searchView": "ReactNode", "loadingView": "ReactNode", "emptyView": "ReactNode", - "errorView": "ReactNode", - "options": "(conversation: CometChat.Conversation) => CometChatConversationOption[]" + "errorView": "ReactNode" } }, "events": [ @@ -134,7 +133,7 @@ description: "Scrollable list of recent one-on-one and group conversations for t `CometChatConversations` is a sidebar list component. It renders recent conversations for the logged-in user and emits the selected `CometChat.Conversation` via `onItemClick`. Wire it to `CometChatMessageHeader`, `CometChatMessageList`, and `CometChatMessageComposer` to build a standard two-panel chat layout. -{/* TODO:IMAGE - CometChatConversations component showing a list of conversations with avatars, names, last messages, timestamps, and unread badges */} + **Live Preview** — interact with the default conversations list. @@ -155,7 +154,6 @@ The component handles: - Paginated fetching with infinite scroll - Real-time updates (new messages, typing indicators, presence changes) - Search filtering -- Swipe/hover options (delete conversation) - Selection mode (single/multiple) --- @@ -371,7 +369,447 @@ Use view props to replace sections of the default UI while keeping the component | `emptyView` | `ReactNode` | Empty state | | `errorView` | `ReactNode` | Error state | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the conversation item */} +#### itemView + +Replace the entire list item row. + +Default: + + + + + +Customized: + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { + CometChatConversations, + CometChatAvatar, + CometChatDate, +} from "@cometchat/chat-uikit-react"; + +function CustomItemViewConversations() { + const getItemView = (conversation: CometChat.Conversation) => { + const title = conversation.getConversationWith().getName(); + const timestamp = conversation?.getLastMessage()?.getSentAt(); + + return ( +
+ + + + + {title} + {timestamp ? ( + + + + ) : null} +
+ ); + }; + + return ; +} +``` +
+ +```css +.conversations__custom-item { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 16px; + width: 100%; +} + +.conversations__custom-item-title { + flex: 1; + font: 500 16px/19.2px Roboto; + color: #141414; +} + +.cometchat-conversations .cometchat-avatar { + border-radius: 8px; + width: 32px; + height: 32px; +} +``` + +
+ +#### leadingView + +Replace the avatar / left section. Typing-aware avatar example. + + + + + +```tsx +import { useEffect, useRef, useState } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { + CometChatConversations, + CometChatAvatar, + useLoggedInUser, +} from "@cometchat/chat-uikit-react"; + +function TypingAwareConversations() { + const [isTyping, setIsTyping] = useState(false); + const typingObjRef = useRef(null); + const loggedInUser = useLoggedInUser(); + + useEffect(() => { + const listenerId = "typing_demo_" + Date.now(); + CometChat.addMessageListener( + listenerId, + new CometChat.MessageListener({ + onTypingStarted: (typingIndicator: CometChat.TypingIndicator) => { + typingObjRef.current = typingIndicator; + setIsTyping(true); + }, + onTypingEnded: (typingIndicator: CometChat.TypingIndicator) => { + if ( + typingObjRef.current && + typingObjRef.current.getSender().getUid() === + typingIndicator.getSender().getUid() + ) { + typingObjRef.current = null; + setIsTyping(false); + } + }, + }) + ); + return () => { + CometChat.removeMessageListener(listenerId); + }; + }, []); + + const getLeadingView = (conversation: CometChat.Conversation) => { + const entity = conversation.getConversationWith(); + const isUser = entity instanceof CometChat.User; + const isGroup = entity instanceof CometChat.Group; + + const isMyTyping = isUser + ? (entity as CometChat.User).getUid() === + typingObjRef.current?.getSender().getUid() && + loggedInUser?.getUid() === typingObjRef.current?.getReceiverId() + : isGroup && + (entity as CometChat.Group).getGuid() === + typingObjRef.current?.getReceiverId(); + + const avatar = isUser + ? (entity as CometChat.User).getAvatar() + : (entity as CometChat.Group).getIcon(); + + return ( +
+ + + + +
+ ); + }; + + return ; +} +``` + +#### titleView + +Replace the name / title text. Inline user status example. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatConversations } from "@cometchat/chat-uikit-react"; + +function StatusTitleConversations() { + const getTitleView = (conversation: CometChat.Conversation) => { + const user = + conversation.getConversationType() === "user" + ? (conversation.getConversationWith() as CometChat.User) + : undefined; + + return ( +
+ + {user + ? conversation.getConversationWith().getName() + " · " + : conversation.getConversationWith().getName()} + + {user && ( + + {user.getStatusMessage()} + + )} +
+ ); + }; + + return ; +} +``` +
+ +```css +.cometchat-conversations .conversations__title-view { + display: flex; + gap: 4px; + width: 100%; +} + +.conversations__title-view-name { + color: #141414; + font: 500 16px/19.2px Roboto; +} + +.conversations__title-view-status { + color: #6852d6; + font: 400 16px/19.2px Roboto; +} +``` + +
+ +#### subtitleView + +Replace the last message preview text. + +Default: + + + + + +Customized: + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatConversations } from "@cometchat/chat-uikit-react"; + +function formatTimestamp(timestamp: number): string { + return new Date(timestamp * 1000).toLocaleString(); +} + +function SubtitleConversations() { + const getSubtitleView = (conversation: CometChat.Conversation) => { + if (conversation.getConversationType() === "user") { + return ( + + Last active:{" "} + {new Date( + (conversation.getConversationWith() as CometChat.User).getLastActiveAt() * 1000 + ).toLocaleString()} + + ); + } + return ( + + Created:{" "} + {new Date( + (conversation.getConversationWith() as CometChat.Group).getCreatedAt() * 1000 + ).toLocaleString()} + + ); + }; + + return ; +} +``` + + +```css +.custom-conversation-subtitle { + overflow: hidden; + color: grey; + text-overflow: ellipsis; + white-space: nowrap; + font: var(--cometchat-font-body-regular); +} +``` + + + +#### trailingView + +Replace the timestamp / badge / right section. Relative time badge example. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatConversations } from "@cometchat/chat-uikit-react"; + +function RelativeTimeConversations() { + const getTrailingView = (conv: CometChat.Conversation) => { + if (!conv.getLastMessage()) return <>; + + const timestamp = conv.getLastMessage()?.getSentAt() * 1000; + const now = Date.now(); + const diffInMinutes = Math.floor((now - timestamp) / (1000 * 60)); + const diffInHours = Math.floor((now - timestamp) / (1000 * 60 * 60)); + + let className = "conversations__trailing-view-min"; + let topLabel = `${diffInMinutes}`; + let bottomLabel = diffInMinutes === 1 ? "Min ago" : "Mins ago"; + + if (diffInHours >= 1 && diffInHours <= 10) { + className = "conversations__trailing-view-hour"; + topLabel = `${diffInHours}`; + bottomLabel = diffInHours === 1 ? "Hour ago" : "Hours ago"; + } else if (diffInHours > 10) { + className = "conversations__trailing-view-date"; + const time = new Date(timestamp); + topLabel = time.toLocaleDateString("en-US", { day: "numeric" }); + bottomLabel = time.toLocaleDateString("en-US", { month: "short", year: "numeric" }); + } + + return ( +
+ {topLabel} + {bottomLabel} +
+ ); + }; + + return ; +} +``` +
+ +```css +.conversations__trailing-view { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 55px; + height: 40px; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.conversations__trailing-view-min { background-color: #e0d4f7; } +.conversations__trailing-view-hour { background-color: #fff3cd; } +.conversations__trailing-view-date { background-color: #f8d7da; } + +.conversations__trailing-view-time { + font: 600 18px Roboto; + color: #4a3f99; + margin-bottom: 4px; +} + +.conversations__trailing-view-status { + font: 600 8px Roboto; + color: #6a5b99; +} + +.cometchat-conversations .cometchat-list-item__trailing-view { + height: 50px; +} +``` + +
+ +#### headerView + +Replace the entire header bar. + + + + + + + +```tsx +import { + CometChatButton, + CometChatConversations, + useLocale, +} from "@cometchat/chat-uikit-react"; + +function CustomHeaderConversations() { + const { getLocalizedString } = useLocale(); + + return ( + +
+ {getLocalizedString("chats")} +
+ { /* handle click */ }}> + + + + } + /> + ); +} +``` +
+ +```css +.conversations__header { + display: flex; + width: 100%; + padding: 8px 16px; + align-items: center; + justify-content: space-between; + gap: 12px; + border-radius: 10px; + border: 1px solid #e8e8e8; + background: #edeafa; +} + +.conversations__header__title { + overflow: hidden; + color: #141414; + text-overflow: ellipsis; + font: 700 24px Roboto; +} + +.conversations__header .cometchat-button .cometchat-button__icon { + background: #141414; +} + +.conversations__header .cometchat-button { + width: 24px; + border: none; + background: transparent; + border-radius: 0; +} +``` + +
### Compound Composition @@ -589,36 +1027,6 @@ Custom sound URL to play when new messages arrive (replaces the built-in sound). --- -### options - -Function that returns context menu options for each conversation item (shown on hover/swipe). - -| | | -| --- | --- | -| Type | `(conversation: CometChat.Conversation) => CometChatConversationOption[]` | -| Default | Default options (delete) | - -```tsx - [ - { - id: "pin", - title: "Pin", - iconURL: pinIcon, - onClick: (conv) => pinConversation(conv), - }, - { - id: "mute", - title: "Mute", - iconURL: muteIcon, - onClick: (conv) => muteConversation(conv), - }, - ]} -/> -``` - ---- - ### onItemClick Callback when a conversation item is clicked. @@ -674,24 +1082,89 @@ Callback when the search bar is clicked. When provided, the search input becomes --- -## CSS Selectors +## CSS Architecture + +The component uses CSS custom properties (design tokens) that are bundled with `@cometchat/chat-uikit-react`. The cascade: + +1. Global tokens (e.g., `--cometchat-primary-color`, `--cometchat-background-color-01`) are set on the `.cometchat` root wrapper. +2. Component CSS (`.cometchat-conversations`) consumes these tokens via `var()` with fallback values. +3. Overrides target `.cometchat-conversations` descendant selectors in a global stylesheet. + +To scope overrides to a single instance when multiple `CometChatConversations` exist on the same page, wrap the component in a container and scope selectors: + +```css +.sidebar-left .cometchat-conversations .cometchat-badge { + background: #e5484d; +} +``` + +Overrides survive component updates because the component never sets inline styles on these elements — all styling flows through CSS classes and custom properties. + +### Key Selectors | Target | Selector | | --- | --- | -| Root container | `.cometchat-conversations` | -| Header | `.cometchat-conversations__header` | -| Search bar | `.cometchat-conversations__search-bar` | -| List container | `.cometchat-conversations__list` | -| Conversation item | `.cometchat-conversations__item` | -| Active item | `.cometchat-conversations__item--active` | -| Item avatar | `.cometchat-conversations__item-avatar` | -| Item title | `.cometchat-conversations__item-title` | -| Item subtitle | `.cometchat-conversations__item-subtitle` | -| Item trailing | `.cometchat-conversations__item-trailing` | -| Unread badge | `.cometchat-conversations__item-unread-count` | -| Empty state | `.cometchat-conversations__empty-state` | -| Error state | `.cometchat-conversations__error-state` | -| Loading state | `.cometchat-conversations__loading-state` | +| Root | `.cometchat-conversations` | +| Header title | `.cometchat-conversations .cometchat-list__header-title` | +| List item | `.cometchat-conversations .cometchat-list-item` | +| Body title | `.cometchat-conversations .cometchat-list-item__body-title` | +| Avatar | `.cometchat-conversations .cometchat-avatar` | +| Avatar text | `.cometchat-conversations .cometchat-avatar__text` | +| Unread badge | `.cometchat-conversations .cometchat-badge` | +| Subtitle text | `.cometchat-conversations .cometchat-conversations__subtitle-text` | +| Status indicator | `.cometchat-conversations .cometchat-status-indicator` | +| Read receipts | `.cometchat-conversations .cometchat-receipts-read` | +| Active item | `.cometchat-conversations__list-item-active .cometchat-list-item` | +| Typing indicator | `.cometchat-conversations__subtitle-typing` | +| Trailing view | `.cometchat-conversations__trailing-view` | + +### Example: Brand-themed conversations + + + + + +```css +.cometchat-conversations .cometchat-conversations__item-title, +.cometchat-conversations .cometchat-conversations__header-title, +.cometchat-conversations .cometchat-avatar__text, +.cometchat-conversations .cometchat-conversations__item-unread-badge, +.cometchat-conversations .cometchat-conversations__item-subtitle-text { + font-family: "SF Pro"; +} + +.cometchat-conversations .cometchat-conversations__header { + background: #fef8f8; + border-bottom: 2px solid #f4b6b8; +} + +.cometchat-conversations .cometchat-avatar { + background: #FAAA75; +} + +.cometchat-conversations .cometchat-status-indicator { + min-width: 10px; + height: 10px; +} + +.cometchat-conversations .cometchat-conversations__item-unread-badge { + background: #F76809; +} + +.cometchat-conversations .cometchat-conversations__item-receipt--read { + background: #FAAA75; +} +``` + +### Customization Matrix + +| What to change | Where | Property/API | Example | +| --- | --- | --- | --- | +| Override behavior on user interaction | Component props | `on` callbacks | `onItemClick={(c) => setActive(c)}` | +| Filter which conversations appear | Component props | `conversationsRequestBuilder` | `conversationsRequestBuilder={new CometChat.ConversationsRequestBuilder().setLimit(10)}` | +| Toggle visibility of UI elements | Component props | `hide` boolean props | `hideReceipts={true}` | +| Replace a section of the list item | Component props | `View` render props | `itemView={(conversation) =>
...
}` | +| Change colors, fonts, spacing | Global CSS | Target `.cometchat-conversations` class | `.cometchat-conversations .cometchat-badge { background: #e5484d; }` | --- diff --git a/ui-kit/react/components/group-members.mdx b/ui-kit/react/components/group-members.mdx index 41c4a17b8..d5e3a2b51 100644 --- a/ui-kit/react/components/group-members.mdx +++ b/ui-kit/react/components/group-members.mdx @@ -326,7 +326,310 @@ Use view props to replace sections of the default UI while keeping the component | `emptyView` | `ReactNode` | Empty state | | `errorView` | `ReactNode` | Error state | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the group member item */} +#### itemView + +Replace the entire list item row. + +Default: + + + + + +Customized: + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { + CometChatAvatar, + CometChatGroupMembers, +} from "@cometchat/chat-uikit-react"; + +function CustomItemViewMembers({ group }: { group: CometChat.Group }) { + const getItemView = (member: CometChat.GroupMember) => { + const scope = member.getScope(); + return ( +
+
+ + + + +
+
+
{member.getName()}
+
+ {scope} +
+
+
+ ); + }; + + return ; +} +``` +
+ +```css +.group-member-list-item { + display: flex; + min-width: 240px; + padding: 8px 16px; + align-items: center; + gap: 12px; + background: #fff; +} + +.group-member-list-item__content { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; +} + +.cometchat-avatar, .cometchat-avatar__image { + border-radius: 10px; +} + +.group-member-list-item__content-name { + overflow: hidden; + color: #141414; + text-overflow: ellipsis; + font: 500 16px Roboto; +} + +.group-member-list-item__content-tag { + display: flex; + padding: 4px 12px; + border-radius: 1000px; + background: #edeafa; + color: #6852d6; + font: 400 12px Roboto; +} + +.group-member-list-item__content-tag-owner { + background: #6852d6; + color: #fff; +} + +.group-member-list-item__content-tag-admin { + border: 1px solid #6852d6; +} + +.group-member-list-item__content-tag-participant { + display: none; +} +``` + +
+ +#### subtitleView + +Replace the subtitle text. Joined date example. + +Default: + + + + + +Customized: + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatGroupMembers } from "@cometchat/chat-uikit-react"; + +function SubtitleMembers({ group }: { group: CometChat.Group }) { + const getSubtitleView = (member: CometChat.GroupMember) => { + const date = new Date(member.getJoinedAt() * 1000).toLocaleDateString(); + return
Joined: {date}
; + }; + + return ; +} +``` +
+ +```css +.group-member-subtitle { + overflow: hidden; + color: #727272; + text-overflow: ellipsis; + white-space: nowrap; + font: 400 14px Roboto; +} +``` + +
+ +#### trailingView + +Replace the right section. Scope tag example. + +Default: + + + + + +Customized: + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatGroupMembers } from "@cometchat/chat-uikit-react"; + +function TrailingViewMembers({ group }: { group: CometChat.Group }) { + const getTrailingView = (member: CometChat.GroupMember) => { + return ( +
+ {member.getScope()} +
+ ); + }; + + return ; +} +``` +
+ +```css +.group-member-scope-tag { + display: flex; + padding: 4px 12px; + border-radius: 1000px; + background: #edeafa; + color: #6852d6; + font: 400 12px Roboto; +} +``` + +
+ +#### headerView + +Replace the entire header bar. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { + CometChatGroupMembers, + CometChatButton, + useLocale, +} from "@cometchat/chat-uikit-react"; + +function CustomHeaderMembers({ group }: { group: CometChat.Group }) { + const { getLocalizedString } = useLocale(); + + return ( + +
+ {getLocalizedString("group_members")} +
+ { /* handle click */ }}> + + + + } + /> + ); +} +``` +
+ +```css +.group-members__header { + display: flex; + width: 100%; + padding: 8px 16px; + align-items: center; + justify-content: space-between; + gap: 12px; + border-radius: 10px; + border: 1px solid #e8e8e8; + background: #edeafa; +} + +.group-members__header__title { + overflow: hidden; + color: #141414; + text-overflow: ellipsis; + font: 700 24px Roboto; +} +``` + +
+ +#### options + +Replace the context menu / hover actions on each member item. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { + CometChatGroupMembers, + type CometChatGroupMemberOption, +} from "@cometchat/chat-uikit-react"; + +function CustomOptionsMembers({ group }: { group: CometChat.Group }) { + const getOptions = (member: CometChat.GroupMember): CometChatGroupMemberOption[] => [ + { + id: "kick", + title: "Kick User", + onClick: (m) => { /* kick logic */ }, + }, + ]; + + return ; +} +``` + + +```css +.cometchat-group-members .cometchat-menu-list__main-menu-item-icon { + background: #f44649; +} + +.cometchat-group-members .cometchat-menu-list__menu { + background: transparent; + box-shadow: none; +} +``` + + ### Compound Composition diff --git a/ui-kit/react/components/groups.mdx b/ui-kit/react/components/groups.mdx index 48eaa12b4..8384d7626 100644 --- a/ui-kit/react/components/groups.mdx +++ b/ui-kit/react/components/groups.mdx @@ -343,7 +343,214 @@ Use view props to replace sections of the default UI while keeping the component | `emptyView` | `ReactNode` | Empty state | | `errorView` | `ReactNode` | Error state | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the group item */} +#### itemView + +Replace the entire list item row. + +Default: + + + + + +Customized: + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatGroups } from "@cometchat/chat-uikit-react"; + +function CustomItemViewGroups() { + const getItemView = (group: CometChat.Group) => { + return ( +
+
+
{group.getName()}
+
JOIN
+
+
+ {group.getMembersCount()} Members • {group.getDescription()} +
+
+ ); + }; + + return ; +} +``` +
+ +```css +.group-list-item { + display: flex; + flex-direction: column; + text-align: left; + min-width: 240px; + padding: 8px 16px; + gap: 4px; + flex: 1 0 0; + border-right: 1px solid #f5f5f5; + background: #fff; +} + +.group-list-item:hover { + background-color: #f5f5f5; +} + +.group-list-item__title-wrapper { + display: flex; + justify-content: space-between; + align-items: center; + align-self: stretch; +} + +.group-list-item__title { + overflow: hidden; + color: #141414; + text-overflow: ellipsis; + font: 500 16px Roboto; +} + +.group-list-item__tail { + display: flex; + padding: 4px 12px; + justify-content: center; + align-items: center; + border-radius: 1000px; + background: #edeafa; + overflow: hidden; + color: #6852d6; + text-overflow: ellipsis; + font: 700 12px Roboto; +} + +.group-list-item__subtitle { + overflow: hidden; + color: #727272; + text-overflow: ellipsis; + white-space: nowrap; + font: 400 14px Roboto; +} +``` + +
+ +#### titleView + +Replace the name / title text. Group type badge inline example. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatGroups } from "@cometchat/chat-uikit-react"; + +function GroupTypeTitleGroups() { + const getTitleView = (group: CometChat.Group) => { + return ( +
+ {group.getName()} + {group.getType()} +
+ ); + }; + + return ; +} +``` +
+ +```css +.groups__title-view { + display: flex; + align-items: center; + gap: 4px; + align-self: stretch; +} + +.groups__title-view-name { + overflow: hidden; + color: #141414; + text-overflow: ellipsis; + font: 500 16px Roboto; +} + +.groups__title-view-type { + color: #fff; + font: 600 8px Roboto; + display: flex; + height: 15px; + padding: 1px 3px; + justify-content: center; + align-items: center; + gap: 4px; + border-radius: 7px; + background: #09c26f; +} + +.groups__title-view-public .groups__title-view-type { + background: #0b7bea; +} +``` + +
+ +#### subtitleView + +Replace the member count subtitle text. + +Default: + + + + + +Customized: + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatGroups } from "@cometchat/chat-uikit-react"; + +function SubtitleGroups() { + const getSubtitleView = (group: CometChat.Group) => { + return ( +
+ {group.getMembersCount()} Members • {group.getDescription()} +
+ ); + }; + + return ; +} +``` +
+ +```css +.cometchat-groups .group-subtitle { + overflow: hidden; + color: #727272; + text-overflow: ellipsis; + white-space: nowrap; + font: 400 14px Roboto; +} +``` + +
### Compound Composition diff --git a/ui-kit/react/components/incoming-call.mdx b/ui-kit/react/components/incoming-call.mdx index 36615fb31..8cade657c 100644 --- a/ui-kit/react/components/incoming-call.mdx +++ b/ui-kit/react/components/incoming-call.mdx @@ -223,7 +223,83 @@ Use view props to replace sections of the default UI while keeping the component | `subtitleView` | `(call: CometChat.Call) => ReactNode` | Call type label | | `trailingView` | `(call: CometChat.Call) => ReactNode` | Trailing section | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the incoming call notification */} +#### leadingView + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatAvatar, CometChatIncomingCall } from "@cometchat/chat-uikit-react"; + +function CustomLeadingIncoming() { + return ( + ( + + + + + )} + /> + ); +} +``` + +#### titleView + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatIncomingCall } from "@cometchat/chat-uikit-react"; + +function CustomTitleIncoming() { + return ( + ( +
{call.getCallInitiator()?.getName()}
+ )} + /> + ); +} +``` + +#### itemView + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatAvatar, CometChatIncomingCall } from "@cometchat/chat-uikit-react"; + +function CustomItemViewIncoming() { + return ( + ( +
+ + + + +
{call.getCallInitiator()?.getName()}
+
+ )} + /> + ); +} +``` ### CSS Styling diff --git a/ui-kit/react/components/message-composer.mdx b/ui-kit/react/components/message-composer.mdx index c9fbac96a..d5bdb8f04 100644 --- a/ui-kit/react/components/message-composer.mdx +++ b/ui-kit/react/components/message-composer.mdx @@ -324,7 +324,79 @@ Use view props to replace sections of the default UI while keeping the component | `auxiliaryButtonView` | `ReactNode` | Additional buttons in the actions area | | `headerView` | `ReactNode` | Header area above the input | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the composer */} +#### attachmentOptions + +Override the default attachment options. + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatMessageComposer } from "@cometchat/chat-uikit-react"; + +function ComposerCustomAttachments({ chatUser }: { chatUser: CometChat.User }) { + return ( + + ); +} +``` + +#### auxiliaryButtonView + +Replace the auxiliary button area. + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatMessageComposer, CometChatButton } from "@cometchat/chat-uikit-react"; + +function ComposerCustomAuxiliary({ chatUser }: { chatUser: CometChat.User }) { + return ( + {}}> + + + } + /> + ); +} +``` + +#### sendButtonView + +Replace the send button. + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatMessageComposer, CometChatButton } from "@cometchat/chat-uikit-react"; + +function ComposerCustomSend({ chatUser }: { chatUser: CometChat.User }) { + return ( + {}}> + + + } + /> + ); +} +``` ### Compound Composition diff --git a/ui-kit/react/components/message-header.mdx b/ui-kit/react/components/message-header.mdx index b80db5d04..c4a216eed 100644 --- a/ui-kit/react/components/message-header.mdx +++ b/ui-kit/react/components/message-header.mdx @@ -362,7 +362,155 @@ Use view props to replace sections of the default UI while keeping the component | `trailingView` | `ReactNode` | Call buttons + overflow menu | | `auxiliaryButtonView` | `ReactNode` | Auxiliary button area | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the message header */} +#### itemView + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatMessageHeader, CometChatAvatar } from "@cometchat/chat-uikit-react"; + +function CustomItemViewHeader({ user }: { user: CometChat.User }) { + return ( + + + + + } + titleView={{user.getName()}} + subtitleView={{user.getStatus()}} + /> + ); +} +``` + +#### titleView + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatMessageHeader } from "@cometchat/chat-uikit-react"; + +function CustomTitleHeader({ user }: { user: CometChat.User }) { + return ( + + + {user.getName() + " • "} + + + {user.getStatusMessage()} + + + } + /> + ); +} +``` + + +```css +.cometchat-message-header .message-header__title-view { + display: flex; + gap: 4px; + width: 100%; +} + +.message-header__title-view-name { + color: #141414; + font: 500 16px/19.2px Roboto; +} + +.message-header__title-view-status { + color: #6852d6; + font: 400 16px/19.2px Roboto; +} +``` + + + +#### subtitleView + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatMessageHeader } from "@cometchat/chat-uikit-react"; + +function CustomSubtitleHeader({ group }: { group: CometChat.Group }) { + return ( + {group.getMembersCount() + " • " + group.getDescription()} + } + /> + ); +} +``` + +#### leadingView + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatMessageHeader, CometChatAvatar } from "@cometchat/chat-uikit-react"; + +function CustomLeadingHeader({ user }: { user: CometChat.User }) { + return ( + + + + + + + {user.getRole()} + + + } + /> + ); +} +``` + + +```css +.message-header__leading-view { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; +} + +.message-header__leading-view-role { + color: #6852d6; + font: 600 8px Roboto; +} +``` + + ### Compound Composition diff --git a/ui-kit/react/components/message-list.mdx b/ui-kit/react/components/message-list.mdx index 9c03a2f6b..685b3e7a9 100644 --- a/ui-kit/react/components/message-list.mdx +++ b/ui-kit/react/components/message-list.mdx @@ -469,7 +469,122 @@ Use view props to replace sections of the default UI while keeping the component | `emptyView` | `ReactNode` | Empty state | | `errorView` | `ReactNode` | Error state | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the message list */} +#### headerView + +Custom view above the message list. + + + + + + + +```tsx +import { useState, useEffect } from "react"; +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatMessageList, CometChatButton } from "@cometchat/chat-uikit-react"; + +function MessageListWithHeader() { + const [chatUser, setChatUser] = useState(); + + useEffect(() => { + CometChat.getUser("uid").then((user) => setChatUser(user)); + }, []); + + return chatUser ? ( + + + Notes + + + Pinned Message + + + Saved Links + + + } + /> + ) : null; +} +``` + + +```css +.header-view { + display: flex; + width: 100%; + padding: 3px 16px; + align-items: flex-start; + gap: 5px; + background: #edeafa; +} + +.header-view .cometchat-button { + width: auto; + height: 32px; + border-radius: 1000px; + border: 1px solid #e8e8e8; + background: #fafafa; +} + +.header-view .cometchat-button__text { + color: #6852d6; + font: 400 12px/14.4px Roboto; +} +``` + + + +#### footerView + +Custom view below the message list. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatMessageList, CometChatButton } from "@cometchat/chat-uikit-react"; + +function MessageListWithFooter({ chatUser }: { chatUser: CometChat.User }) { + return ( + + + Ice Breakers + + + +1-212-456-7890 + + + } + /> + ); +} +``` + + +```css +.footer-view { + display: flex; + width: 100%; + padding: 3px 16px; + align-items: flex-start; + gap: 5px; + background: #edeafa; +} +``` + + ### Compound Composition diff --git a/ui-kit/react/components/outgoing-call.mdx b/ui-kit/react/components/outgoing-call.mdx index d9fbf6e82..629614030 100644 --- a/ui-kit/react/components/outgoing-call.mdx +++ b/ui-kit/react/components/outgoing-call.mdx @@ -192,7 +192,133 @@ Use view props to replace sections of the default UI while keeping the component | `avatarView` | `ReactNode` | Receiver avatar | | `cancelButtonView` | `ReactNode` | End-call button | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the outgoing call screen */} +#### titleView + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatOutgoingCall } from "@cometchat/chat-uikit-react"; + +function OutgoingCallCustomTitle({ call }: { call: CometChat.Call }) { + return ( + + {call.getCallInitiator().getName()} {" <> "} {call.getCallReceiver().getName()} + + } + /> + ); +} +``` + + +```css +.outgoing-call__title { + color: #141414; + text-align: center; + font: 500 24px Roboto; +} +``` + + + +#### subtitleView + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatOutgoingCall } from "@cometchat/chat-uikit-react"; + +function OutgoingCallCustomSubtitle({ call }: { call: CometChat.Call }) { + return ( + +
+ {"Calling..."} +
+ } + /> + ); +} +``` +
+ +```css +.outgoing-call__subtitle { + display: flex; + justify-content: center; + align-items: flex-start; + gap: 8px; + color: #727272; + text-align: center; + font: 400 16px Roboto; +} + +.outgoing-call__subtitle-icon { + background: #a1a1a1; + height: 24px; + width: 24px; +} +``` + +
+ +#### avatarView + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatOutgoingCall, CometChatAvatar } from "@cometchat/chat-uikit-react"; + +function OutgoingCallCustomAvatar({ call }: { call: CometChat.Call }) { + return ( + + + + + + + } + /> + ); +} +``` + + +```css +.outgoing-call__avatar .cometchat-avatar { + width: 160px; + height: 160px; + border-radius: 20px; +} +``` + + ### CSS Styling diff --git a/ui-kit/react/components/search.mdx b/ui-kit/react/components/search.mdx index 2de60e17c..bb0e7541d 100644 --- a/ui-kit/react/components/search.mdx +++ b/ui-kit/react/components/search.mdx @@ -410,7 +410,215 @@ Use view props to replace sections of the default UI while keeping the component | `messageSubtitleView` | `(message) => ReactNode` | Subtitle of message result | | `messageTrailingView` | `(message) => ReactNode` | Trailing section of message result | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the search results */} +#### messageItemView + +Replace the entire message list item in search results. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatSearch } from "@cometchat/chat-uikit-react"; + +function SearchCustomMessageItem() { + const getMessageItemView = (message: CometChat.BaseMessage) => ( +
+
+ {message.getSender()?.getName()}: +
+
+ {message instanceof CometChat.TextMessage + ? (message as CometChat.TextMessage).getText() + : message.getType()} +
+
+ ); + + return ; +} +``` +
+ +```css +.cometchat-search__message-list-item { + background: var(--cometchat-extended-primary-color-100); + border-bottom: 1px solid var(--cometchat-border-color-highlight); + padding: var(--cometchat-padding-3) var(--cometchat-padding-4); + display: flex; + justify-content: flex-start; + gap: var(--cometchat-padding-2); +} + +.cometchat-search__message-list-item-sender { + color: var(--cometchat-text-color-highlight); + font: var(--cometchat-font-body-regular); +} + +.cometchat-search__message-list-item-text { + color: var(--cometchat-text-color-secondary); + font: var(--cometchat-font-body-regular); +} +``` + +
+ +#### messageLeadingView + +Replace the message avatar / left section. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatSearch } from "@cometchat/chat-uikit-react"; + +function SearchCustomMessageLeading() { + const getMessageLeadingView = (message: CometChat.BaseMessage) => ( +
+ +
+ ); + + return ; +} +``` +
+ +```css +.cometchat-search__message-list-item-leading-view { + height: 48px; + width: 48px; + border-radius: var(--cometchat-radius-2); + background: var(--cometchat-extended-primary-color-500); + display: flex; + align-items: center; + justify-content: center; +} + +.cometchat-search__message-list-item-leading-view img { + height: 32px; + width: 32px; +} +``` + +
+ +#### messageTitleView + +Replace the message title text. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatSearch } from "@cometchat/chat-uikit-react"; + +function SearchCustomMessageTitle() { + const getMessageTitleView = (message: CometChat.BaseMessage) => ( +
+
+ {message.getSender()?.getName()} +
+ | +
+ {message.getSender().getRole() ?? "Pro User"} +
+
+ ); + + return ; +} +``` +
+ +```css +.cometchat-search__message-list-item-title { + display: flex; + align-items: center; + gap: var(--cometchat-spacing-1); +} + +.cometchat-search__message-list-item-title-text { + font: var(--cometchat-font-heading4-medium); + color: var(--cometchat-text-color-secondary); +} + +.cometchat-search__message-list-item-title-role { + font: var(--cometchat-font-heading4-medium); + color: var(--cometchat-text-color-highlight); + text-decoration: underline; +} +``` + +
+ +#### messageSubtitleView + +Replace the message subtitle text. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatSearch } from "@cometchat/chat-uikit-react"; + +function SearchCustomMessageSubtitle() { + const getMessageSubtitleView = (message: CometChat.BaseMessage) => ( +
+
+ {message.getSender()?.getName()}: +
+
+ {message instanceof CometChat.TextMessage + ? (message as CometChat.TextMessage).getText() + : message.getType()} +
+
+ ); + + return ; +} +``` +
+ +```css +.cometchat-search__message-list-item-subtitle { + background: var(--cometchat-extended-primary-color-100); + padding: var(--cometchat-padding-1); + display: flex; + justify-content: flex-start; + gap: var(--cometchat-padding-2); + width: 100%; +} + +.cometchat-search__message-list-item-subtitle-sender { + color: var(--cometchat-text-color-highlight); + font: var(--cometchat-font-body-regular); +} + +.cometchat-search__message-list-item-subtitle-text { + color: var(--cometchat-text-color-secondary); + font: var(--cometchat-font-body-regular); +} +``` + +
### Compound Composition diff --git a/ui-kit/react/components/thread-header.mdx b/ui-kit/react/components/thread-header.mdx index e46875016..201b64ab0 100644 --- a/ui-kit/react/components/thread-header.mdx +++ b/ui-kit/react/components/thread-header.mdx @@ -285,7 +285,23 @@ Use view props to replace sections of the default UI while keeping the component | `messageBubbleView` | `ReactNode` | Parent message bubble | | `subtitleView` | `ReactNode` | Subtitle below the title | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the thread header */} +#### messageBubbleView + +Replace the parent message bubble with a custom view. + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatThreadHeader } from "@cometchat/chat-uikit-react"; + +function CustomBubbleThread({ parentMessage }: { parentMessage: CometChat.BaseMessage }) { + return ( + Custom bubble view} + /> + ); +} +``` ### Compound Composition diff --git a/ui-kit/react/components/users.mdx b/ui-kit/react/components/users.mdx index 6f7a78df8..8b35a6c2a 100644 --- a/ui-kit/react/components/users.mdx +++ b/ui-kit/react/components/users.mdx @@ -305,7 +305,265 @@ Use view props to replace sections of the default UI while keeping the component | `emptyView` | `ReactNode` | Empty state | | `errorView` | `ReactNode` | Error state | -{/* TODO:IMAGE - Annotated diagram showing which view slot maps to which part of the user item */} +#### itemView + +Replace the entire list item row. + +Default: + + + + + +Customized: + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatUsers } from "@cometchat/chat-uikit-react"; + +function UsersDemo() { + const getItemView = (user: CometChat.User) => { + const status = user.getStatus(); + + return ( +
+ {user.getName()} + {user.getStatus()} +
+ ); + }; + + return ; +} +``` +
+ +```css +.cometchat-users__list-item { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 16px; +} + +.cometchat-users__list-item-active { + background: rgba(9, 194, 111, 0.1); +} +``` + +
+ +#### leadingView + +Replace the avatar / left section. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatUsers, CometChatAvatar } from "@cometchat/chat-uikit-react"; + +function LeadingViewUsers() { + const getLeadingView = (user: CometChat.User) => { + return ( +
+ + + + +
+ ); + }; + + return ; +} +``` +
+ +```css +.cometchat-users .users__leading-view .cometchat-avatar { + border-radius: 8px; + height: 48px; + width: 48px; +} + +.users__leading-view { + position: relative; +} +``` + +
+ +#### titleView + +Replace the name / title text. Role badge inline example. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatUsers } from "@cometchat/chat-uikit-react"; + +function TitleViewUsers() { + const getTitleView = (user: CometChat.User) => { + return ( +
+ {user.getName()} + {user.getRole()} +
+ ); + }; + + return ; +} +``` +
+ +```css +.users__title-view { + display: flex; + align-items: center; + gap: 4px; + align-self: stretch; +} + +.users__title-view-name { + overflow: hidden; + color: #141414; + text-overflow: ellipsis; + font: 500 16px Roboto; +} + +.users__title-view-type { + color: #fff; + font: 600 8px Roboto; + display: flex; + height: 15px; + padding: 1px 3px; + justify-content: center; + align-items: center; + border-radius: 7px; + background: #09c26f; +} +``` + +
+ +#### subtitleView + +Replace the subtitle text for each user. + +Default: + + + + + +Customized: + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatUsers } from "@cometchat/chat-uikit-react"; + +function SubtitleViewUsers() { + const getSubtitleView = (user: CometChat.User) => { + return ( +
+ {user.getStatusMessage() || user.getStatus()} +
+ ); + }; + + return ; +} +``` +
+ +```css +.users-subtitle { + overflow: hidden; + color: #727272; + text-overflow: ellipsis; + white-space: nowrap; + font: 400 14px Roboto; +} +``` + +
+ +#### trailingView + +Replace the right section. + + + + + + + +```tsx +import { CometChat } from "@cometchat/chat-sdk-javascript"; +import { CometChatUsers } from "@cometchat/chat-uikit-react"; + +function TrailingViewUsers() { + const getTrailingView = (user: CometChat.User) => { + const tag = user.getTags()?.[0] ?? ""; + return ( +
+ {tag} +
+ ); + }; + + return ; +} +``` +
+ +```css +.users__trailing-view { + display: flex; + width: 33px; + padding: 5px 3px; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 3px; + border-radius: 4px; + background: #6852d6; +} + +.users__trailing-view-text { + font: 600 8px Inter; + color: white; +} +``` + +
### Compound Composition From ca23e4fdd81424c7fec683777c86ae5211bfec03 Mon Sep 17 00:00:00 2001 From: shagun-cometchat Date: Wed, 3 Jun 2026 19:15:48 +0530 Subject: [PATCH 2/2] expand message bubble styling guide with selector patterns and CSS variables --- ui-kit/react/theme/message-bubble-styling.mdx | 963 ++++++++++++++++-- 1 file changed, 869 insertions(+), 94 deletions(-) diff --git a/ui-kit/react/theme/message-bubble-styling.mdx b/ui-kit/react/theme/message-bubble-styling.mdx index 56d17da25..d6197a748 100644 --- a/ui-kit/react/theme/message-bubble-styling.mdx +++ b/ui-kit/react/theme/message-bubble-styling.mdx @@ -1,24 +1,87 @@ --- title: "Message Bubble Styling" -description: "Customize message bubble appearance including colors, borders, spacing, and alignment." +description: "Customize incoming and outgoing message bubble colors, backgrounds, and styles using CSS variables and class selectors in the CometChat React UI Kit." --- | Field | Value | | --- | --- | -| Bubble wrapper class | `.cometchat-message-bubble` | -| Incoming content | `.cometchat-message-bubble__content--incoming` | -| Outgoing content | `.cometchat-message-bubble__content--outgoing` | -| Key tokens | `--cometchat-neutral-color-300` (incoming bg), `--cometchat-primary-color` (outgoing bg) | +| Goal | Customize message bubble appearance (colors, backgrounds) per direction and message type | +| Where | `App.css` (global) — imported in app entry via `import "./App.css";` | +| Base selector | `.cometchat .cometchat-message-bubble-(incoming\|outgoing) .cometchat-message-bubble__body` | +| Type modifier | Append `.cometchat-message-bubble__-message` to target specific types (`text`, `image`, `video`, `audio`, `file`) | +| Key tokens | `--cometchat-primary-color` (outgoing bg), `--cometchat-neutral-color-300` (incoming bg) | +| Constraints | Global CSS only (no CSS Modules), no `!important`, type selectors override generic bubble selectors | -## Overview +Message bubble styling uses distinct CSS classes for incoming and outgoing messages. Each message type (text, image, video, audio, file, etc.) has predefined classes for default styling, customizable via CSS variable overrides. -Message bubbles are the core visual element of the chat. This page covers how to customize their appearance — background colors, border radius, spacing, and text colors — using CSS variable overrides. + +**Prerequisites before applying any CSS customization:** +1. All selectors assume the UI Kit renders under a `.cometchat` root wrapper +2. Import your CSS file at the app entry: `import "./App.css";` in `App.tsx` +3. Use **global CSS** (not CSS Modules with hashed class names) — hashed selectors won't match + -{/* TODO:IMAGE - Side-by-side comparison of default vs custom-styled bubbles */} +--- + +## Selector Pattern + +Use this table to construct the correct CSS selector for any message bubble target. AI agents should use this pattern to generalize — do not guess selectors. + +| Target | Selector Pattern | +| --- | --- | +| All bubbles | `.cometchat .cometchat-message-bubble .cometchat-message-bubble__body` | +| Outgoing bubbles (all types) | `.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body` | +| Incoming bubbles (all types) | `.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body` | +| Specific type (outgoing) | `.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__-message` | +| Specific type (incoming) | `.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__-message` | +| Action bubbles (no direction) | `.cometchat .cometchat-message-bubble__body .cometchat-action-bubble` | + + + +`` + +`` is one of `text`, `image`, `video`, `audio`, `file` + + + +Link Preview Bubbles + +It reuse the `text-message` type selector since link previews are rendered inside text messages. + + +--- + +## CSS Variable Reference + +These are the CSS variables (tokens) used across message bubble styling. This table tells you exactly what each token controls — do not assume a token affects something not listed here. + +| Variable | What It Controls | Default (Light) | Commonly Used On | +| --- | --- | --- | --- | +| `--cometchat-primary-color` | Outgoing bubble background, primary accent | `#6852d6` | Outgoing bubbles (all types), action bubble accent | +| `--cometchat-neutral-color-300` | Incoming bubble background | `#E8E8E8` | Incoming bubbles (all types) | +| `--cometchat-extended-primary-color-900` | Outgoing bubble shade/gradient variant | `#5d49be` | Outgoing text bubble, link preview | +| `--cometchat-extended-primary-color-800` | Outgoing bubble secondary shade | `#5745b4` | Direct call outgoing bubble | +| `--cometchat-extended-primary-color-700` | Outgoing bubble tertiary shade | `#4f3ea3` | Poll outgoing bubble | +| `--cometchat-neutral-color-400` | Incoming bubble secondary shade | varies | Link preview incoming | +| `--cometchat-primary-button-background` | Primary button fill inside bubbles | matches primary | Whiteboard/document incoming buttons | +| `--cometchat-text-color-secondary` | Secondary/caption text color | varies | Action bubble text | +| `--cometchat-icon-color-secondary` | Secondary icon color | varies | Action bubble icons | +| `--cometchat-border-color-default` | Default border color | varies | Action bubble borders | + +--- + + +**CSS Specificity & Precedence Rules:** +1. Message-type selectors (e.g., `__text-message`) override "All Message Bubbles" selectors +2. Always keep the `.cometchat` prefix to avoid leaking styles into the host app +3. Component-level variable overrides (`.cometchat-message-list { --var: val }`) override global overrides (`.cometchat { --var: val }`) +4. CSS variable overrides only affect properties the UI Kit theme binds to that variable — they do NOT change layout or spacing +5. `!important` should never be needed — if it is, your selector specificity is wrong + --- @@ -28,160 +91,866 @@ Each message bubble has this DOM structure: ``` .cometchat-message-bubble - ├── .cometchat-message-bubble__leading (avatar) - ├── .cometchat-message-bubble__body - │ ├── .cometchat-message-bubble__header (sender name) - │ ├── .cometchat-message-bubble__reply (quoted message) - │ ├── .cometchat-message-bubble__content--incoming / --outgoing - │ │ └── (plugin bubble content: text, image, file, etc.) - │ ├── .cometchat-message-bubble__footer (reactions) - │ ├── .cometchat-message-bubble__status-info (timestamp + receipts) - │ └── .cometchat-message-bubble__thread (reply count) - └── .cometchat-message-bubble__bottom (moderation) + ├── .cometchat-message-bubble__leading-view (avatar) + ├── .cometchat-message-bubble__header-view (sender name) + ├── .cometchat-message-bubble__body-container + │ ├── .cometchat-message-bubble__body-wrapper + │ │ ├── .cometchat-message-bubble__body + │ │ │ ├── .cometchat-message-bubble__body-reply-view (quoted message) + │ │ │ ├── .cometchat-message-bubble__body-content-view (plugin bubble content) + │ │ │ └── .cometchat-message-bubble__body-status-info-view (timestamp + receipts) + │ │ ├── .cometchat-message-bubble__body-footer-view (reactions) + │ │ ├── .cometchat-message-bubble__body-thread-view (reply count) + │ │ └── .cometchat-message-bubble__body-bottom-view (moderation) + │ └── .cometchat-message-bubble__options (context menu) ``` --- -## Customizing Bubble Colors +## Incoming & Outgoing Messages + +Incoming and outgoing messages have different styling by default, allowing users to visually separate their own messages from others'. Here, we show both the default view and examples of customizations for these message bubbles. + +Shown below is the default chat interface. + + + + -### Incoming Bubble Background +*** +### Styling + +#### Outgoing Message Bubbles + +**Selectors:** ```css -.cometchat-message-bubble__content--incoming { - background: #f0f0f0; +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body +``` + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Outgoing bubble background | +| `--cometchat-extended-primary-color-900` | Outgoing bubble shade | + +The customized chat interface is displayed below. + + + + + +Use the following code to achieve the customization shown above. + +```css title="App.css" +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body { + --cometchat-primary-color: #f76808; + --cometchat-extended-primary-color-900: #fbaa75; } ``` -### Outgoing Bubble Background +**Expected result:** All outgoing message bubbles change from purple to orange (#f76808) with a lighter orange shade (#fbaa75). + +*** +#### Incoming Message Bubbles + +**Selectors:** ```css -.cometchat-message-bubble__content--outgoing { - background: #6852d6; +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body +``` + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-neutral-color-300` | Incoming bubble background | + +The customized chat interface is displayed below. + + + + + +Use the following code to achieve the customization shown above. + +```css title="App.css" +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body { + --cometchat-neutral-color-300: #f76808; } ``` -### Using CSS Variables (Recommended) +**Expected result:** All incoming message bubbles change from white/light to orange (#f76808). -Override the tokens on `.cometchat` — this is the simplest and most reliable approach: +*** +#### All Message Bubbles + +**Selectors:** ```css -.cometchat { - /* Incoming bubble background */ - --cometchat-neutral-color-300: #e3f2fd; +.cometchat .cometchat-message-bubble .cometchat-message-bubble__body +``` + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-neutral-color-300` | Incoming bubble background | +| `--cometchat-primary-color` | Outgoing bubble background | +| `--cometchat-extended-primary-color-900` | Outgoing bubble shade | + +The customized chat interface is displayed below. - /* Outgoing bubble background (uses primary color) */ - --cometchat-primary-color: #1976d2; + + + + +Use the following code to achieve the customization shown above. + +```css title="App.css" +.cometchat .cometchat-message-bubble .cometchat-message-bubble__body { + --cometchat-neutral-color-300: #f76808; + --cometchat-primary-color: #f76808; + --cometchat-extended-primary-color-900: #fbaa75; } ``` - -Changing `--cometchat-neutral-color-300` affects all elements that use it (borders, dividers, etc.), not just bubbles. For bubble-only changes, use the attribute selector approach or wrap the message list in your own class. - +**Expected result:** Both incoming and outgoing bubbles use orange (#f76808), with outgoing shade set to lighter orange (#fbaa75). ---- +*** -## Customizing Bubble Shape +### Complete End-to-End Example -### Border Radius +To apply custom bubble colors in your app: + +**Step 1:** Add to `App.css`: ```css -.cometchat-message-bubble__content--incoming, -.cometchat-message-bubble__content--outgoing { - border-radius: 16px; +/* Custom outgoing bubbles */ +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body { + --cometchat-primary-color: #f76808; + --cometchat-extended-primary-color-900: #fbaa75; +} + +/* Custom incoming bubbles */ +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body { + --cometchat-neutral-color-300: #feede1; } ``` -### Remove Rounded Corners +**Step 2:** Ensure `App.tsx` imports the CSS: +```tsx +import "./App.css"; +// ... render CometChat UI Kit components +``` + +**Expected result:** Outgoing bubbles use orange (#f76808) with lighter shade (#fbaa75); incoming bubbles use light peach (#feede1). + +*** + +## Message Types + +CometChat UI Kit includes classes for various message types. Below are examples of default & customised views for each message type, along with the relevant CSS code snippets so that you can quickly get up to speed with CSS customization. + +*** + +### Text Message Bubble + +**Selectors:** + + ```css -.cometchat-message-bubble__content--incoming, -.cometchat-message-bubble__content--outgoing { - border-radius: 0; +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__text-message +``` + + +```css +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__text-message +``` + + + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Outgoing text bubble background | +| `--cometchat-neutral-color-300` | Incoming text bubble background | + +Shown below is the default chat interface. + + + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + +```css +/* Outgoing Text Message Bubble */ +.cometchat + .cometchat-message-bubble-outgoing + .cometchat-message-bubble__body.cometchat-message-bubble__text-message { + --cometchat-primary-color: #f76808; +} + +/* Incoming Text Message Bubble */ +.cometchat + .cometchat-message-bubble-incoming + .cometchat-message-bubble__body.cometchat-message-bubble__text-message { + --cometchat-neutral-color-300: #feede1; } ``` + + ---- +**Expected result:** Outgoing text bubbles change to orange (#f76808); incoming text bubbles change to light peach (#feede1). -## Customizing Bubble Spacing +*** -### Gap Between Bubbles +### Image Message Bubble +**Selectors:** + + +```css +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__image-message +``` + + ```css -.cometchat-message-bubble { - margin-bottom: 16px; +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__image-message +``` + + + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Outgoing image bubble background | +| `--cometchat-neutral-color-300` | Incoming image bubble background | + +Shown below is the default chat interface. + + + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + +```css +/* Outgoing Image Message Bubble */ +.cometchat + .cometchat-message-bubble-outgoing + .cometchat-message-bubble__body.cometchat-message-bubble__image-message { + --cometchat-primary-color: #f76808; +} + +/* Incoming Image Message Bubble */ +.cometchat + .cometchat-message-bubble-incoming + .cometchat-message-bubble__body.cometchat-message-bubble__image-message { + --cometchat-neutral-color-300: #feede1; } ``` + + + +**Expected result:** Outgoing image bubbles change to orange (#f76808); incoming image bubbles change to light peach (#feede1). -### Content Padding +*** +### Video Message Bubble + +**Selectors:** + + +```css +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__video-message +``` + + ```css -.cometchat-message-bubble__content--incoming, -.cometchat-message-bubble__content--outgoing { - padding: 12px 16px; +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__video-message +``` + + + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Outgoing video bubble background | +| `--cometchat-neutral-color-300` | Incoming video bubble background | + +Shown below is the default chat interface. + + + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + +```css +/* Outgoing Video Message Bubble */ +.cometchat + .cometchat-message-bubble-outgoing + .cometchat-message-bubble__body.cometchat-message-bubble__video-message { + --cometchat-primary-color: #f76808; +} + +/* Incoming Video Message Bubble */ +.cometchat + .cometchat-message-bubble-incoming + .cometchat-message-bubble__body.cometchat-message-bubble__video-message { + --cometchat-neutral-color-300: #feede1; } ``` + + ---- +**Expected result:** Outgoing video bubbles change to orange (#f76808); incoming video bubbles change to light peach (#feede1). + +*** + +### Audio Message Bubble + +**Selectors:** + + +```css +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__audio-message +``` + + +```css +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__audio-message +``` + + + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Outgoing audio bubble background, incoming audio accent | +| `--cometchat-neutral-color-300` | Incoming audio bubble background | + +Shown below is the default chat interface. + + + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + +```css +/* Outgoing Audio Message Bubble */ +.cometchat + .cometchat-message-bubble-outgoing + .cometchat-message-bubble__body.cometchat-message-bubble__audio-message { + --cometchat-primary-color: #f76808; +} + +/* Incoming Audio Message Bubble */ +.cometchat + .cometchat-message-bubble-incoming + .cometchat-message-bubble__body.cometchat-message-bubble__audio-message { + --cometchat-primary-color: #f76808; + --cometchat-neutral-color-300: #feede1; +} +``` + + -## Customizing Text Colors +**Expected result:** Outgoing audio bubbles change to orange (#f76808); incoming audio bubbles change to light peach (#feede1) with orange accent for playback controls. -### Incoming Message Text +*** +### File Message Bubble + +**Selectors:** + + +```css +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__file-message +``` + + +```css +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__file-message +``` + + + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Outgoing file bubble background, incoming file accent | +| `--cometchat-neutral-color-300` | Incoming file bubble background | + +Shown below is the default chat interface. + + + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + ```css -.cometchat-text-bubble--incoming { - color: #333333; +/* Outgoing File Message Bubble */ +.cometchat + .cometchat-message-bubble-outgoing + .cometchat-message-bubble__body.cometchat-message-bubble__file-message { + --cometchat-primary-color: #f76808; +} + +/* Incoming File Message Bubble */ +.cometchat + .cometchat-message-bubble-incoming + .cometchat-message-bubble__body.cometchat-message-bubble__file-message { + --cometchat-primary-color: #f76808; + --cometchat-neutral-color-300: #feede1; } ``` + + + +**Expected result:** Outgoing file bubbles change to orange (#f76808); incoming file bubbles change to light peach (#feede1) with orange file icon accent. + +*** -### Outgoing Message Text +### Action Message Bubble +Action messages (e.g., "User joined the group") use a different selector pattern — they are not directional (no incoming/outgoing). + +**Selector:** +- `.cometchat .cometchat-message-bubble__body .cometchat-action-bubble` + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Action bubble accent color | +| `background-color` | Action bubble background (direct CSS property, not a variable) | +| `--cometchat-text-color-secondary` | Action bubble text color | +| `--cometchat-icon-color-secondary` | Action bubble icon color | +| `--cometchat-border-color-default` | Action bubble border color | + +Shown below is the default chat interface. + + + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + ```css -.cometchat-text-bubble--outgoing { - color: #ffffff; +.cometchat .cometchat-message-bubble__body .cometchat-action-bubble { + --cometchat-primary-color: #f76808; + background-color: #feede1; + --cometchat-text-color-secondary: #f76808; + --cometchat-icon-color-secondary: #f76808; + --cometchat-border-color-default: #f76808; } ``` + + ---- +**Expected result:** Action message banners change to light peach background (#feede1) with orange text, icons, and borders (#f76808). + +*** + +### Extensions + +#### Collaborative Whiteboard Bubble + +**Selectors:** + + +```css +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__text-message +``` + + +```css +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__text-message +``` + + + + +In v7, collaborative whiteboard messages use the `text-message` type class internally. + + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Bubble accent and background | +| `--cometchat-primary-button-background` | Incoming whiteboard "Open" button fill | +| `--cometchat-neutral-color-300` | Incoming bubble background | + +Shown below is the default chat interface. -## Customizing Timestamp & Receipts + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + ```css -.cometchat-message-bubble__status-info { - font-size: 11px; - color: #999999; +/* Outgoing Collaborative Whiteboard Bubble */ +.cometchat + .cometchat-message-bubble-outgoing + .cometchat-message-bubble__body.cometchat-message-bubble__text-message { + --cometchat-primary-color: #f76808; +} + +/* Incoming Collaborative Whiteboard Bubble */ +.cometchat + .cometchat-message-bubble-incoming + .cometchat-message-bubble__body.cometchat-message-bubble__text-message { + --cometchat-primary-color: #f76808; + --cometchat-primary-button-background: #f76808; + --cometchat-neutral-color-300: #feede1; } ``` + + ---- +**Expected result:** Outgoing whiteboard bubbles change to orange (#f76808); incoming whiteboard bubbles change to light peach (#feede1) with orange button and accent. + +*** -## Full Example: Custom Bubble Theme +#### Collaborative Document Bubble -```css title="src/bubble-overrides.css" -/* Rounded bubbles with custom colors */ -.cometchat-message-bubble__content--incoming { - background: #e8f5e9; - border-radius: 18px 18px 18px 4px; +**Selectors:** + + +```css +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__text-message +``` + + +```css +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__text-message +``` + + + + +In v7, collaborative document messages use the `text-message` type class internally. + + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Bubble accent and background | +| `--cometchat-primary-button-background` | Incoming document "Open" button fill | +| `--cometchat-neutral-color-300` | Incoming bubble background | + +Shown below is the default chat interface. + + + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + +```css +/* Outgoing Collaborative Document Bubble */ +.cometchat + .cometchat-message-bubble-outgoing + .cometchat-message-bubble__body.cometchat-message-bubble__text-message { + --cometchat-primary-color: #f76808; } -.cometchat-message-bubble__content--outgoing { - background: #1b5e20; - border-radius: 18px 18px 4px 18px; +/* Incoming Collaborative Document Bubble */ +.cometchat + .cometchat-message-bubble-incoming + .cometchat-message-bubble__body.cometchat-message-bubble__text-message { + --cometchat-primary-color: #f76808; + --cometchat-primary-button-background: #f76808; + --cometchat-neutral-color-300: #feede1; } +``` + + + +**Expected result:** Outgoing document bubbles change to orange (#f76808); incoming document bubbles change to light peach (#feede1) with orange button and accent. -.cometchat-text-bubble--incoming { - color: #1b5e20; +*** + +#### Polls Bubble + +**Selectors:** + + +```css +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__text-message +``` + + +```css +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__text-message +``` + + + + +In v7, poll messages use the `text-message` type class internally. + + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Bubble accent and background | +| `--cometchat-extended-primary-color-700` | Outgoing poll progress bar shade | +| `--cometchat-neutral-color-300` | Incoming bubble background | + +Shown below is the default chat interface. + + + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + +```css +/* Outgoing Poll Message Bubble */ +.cometchat + .cometchat-message-bubble-outgoing + .cometchat-message-bubble__body.cometchat-message-bubble__text-message { + --cometchat-primary-color: #f76808; + --cometchat-extended-primary-color-700: #fbaa75; } -.cometchat-text-bubble--outgoing { - color: #ffffff; +/* Incoming Poll Message Bubble */ +.cometchat + .cometchat-message-bubble-incoming + .cometchat-message-bubble__body.cometchat-message-bubble__text-message { + --cometchat-primary-color: #f76808; + --cometchat-neutral-color-300: #feede1; } +``` + + + +**Expected result:** Outgoing poll bubbles change to orange (#f76808) with lighter progress bars (#fbaa75); incoming poll bubbles change to light peach (#feede1) with orange accent. + +*** + +#### Stickers Bubble + +**Selectors:** + + +```css +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__image-message +``` + + +```css +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__image-message +``` + + + + +In v7, sticker messages use the `image-message` type class internally. + + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Outgoing sticker bubble background | +| `--cometchat-neutral-color-300` | Incoming sticker bubble background | + +Shown below is the default chat interface. -/* Smaller timestamp */ -.cometchat-message-bubble__status-info { - font-size: 10px; - opacity: 0.7; + + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + +```css +/* Outgoing Sticker Bubble */ +.cometchat + .cometchat-message-bubble-outgoing + .cometchat-message-bubble__body.cometchat-message-bubble__image-message { + --cometchat-primary-color: #f76808; +} + +/* Incoming Sticker Bubble */ +.cometchat + .cometchat-message-bubble-incoming + .cometchat-message-bubble__body.cometchat-message-bubble__image-message { + --cometchat-neutral-color-300: #feede1; +} +``` + + + +**Expected result:** Outgoing sticker bubbles change to orange (#f76808); incoming sticker bubbles change to light peach (#feede1). + +*** + +#### Link Preview Bubble + +Link previews render inside text message bubbles, so they use the `text-message` type selector. + +**Selectors:** + + +```css +.cometchat .cometchat-message-bubble-outgoing .cometchat-message-bubble__body.cometchat-message-bubble__text-message +``` + + +```css +.cometchat .cometchat-message-bubble-incoming .cometchat-message-bubble__body.cometchat-message-bubble__text-message +``` + + + +**Tokens used:** + +| Token | Controls | +| --- | --- | +| `--cometchat-primary-color` | Outgoing link preview bubble background | +| `--cometchat-extended-primary-color-900` | Outgoing link preview shade | +| `--cometchat-neutral-color-400` | Incoming link preview secondary shade | +| `--cometchat-neutral-color-300` | Incoming link preview bubble background | + + +Styling link preview bubbles also affects regular text message bubbles since they share the same `__text-message` selector. This is by design — link previews are a sub-feature of text messages. + + +Shown below is the default chat interface. + + + + + +The customized chat interface is displayed below. + + + + + +**Complete CSS:** + + + +```css +/* Outgoing Link Preview Bubble */ +.cometchat + .cometchat-message-bubble-outgoing + .cometchat-message-bubble__body.cometchat-message-bubble__text-message { + --cometchat-primary-color: #f76808; + --cometchat-extended-primary-color-900: #fbaa75; +} + +/* Incoming Link Preview Bubble */ +.cometchat + .cometchat-message-bubble-incoming + .cometchat-message-bubble__body.cometchat-message-bubble__text-message { + --cometchat-neutral-color-400: #fbaa75; + --cometchat-neutral-color-300: #feede1; } ``` + + + +**Expected result:** Outgoing link preview bubbles change to orange (#f76808) with lighter shade (#fbaa75); incoming link preview bubbles change to light peach (#feede1) with orange secondary shade (#fbaa75). --- @@ -192,16 +961,22 @@ Class names are plain, stable BEM names that you can target directly: | Target | Selector | | --- | --- | | Bubble wrapper | `.cometchat-message-bubble` | -| Leading (avatar) | `.cometchat-message-bubble__leading` | +| Leading view (avatar) | `.cometchat-message-bubble__leading-view` | +| Header view (sender name) | `.cometchat-message-bubble__header-view` | +| Sender name | `.cometchat-message-bubble__sender-name` | +| Body container | `.cometchat-message-bubble__body-container` | +| Body wrapper | `.cometchat-message-bubble__body-wrapper` | | Body | `.cometchat-message-bubble__body` | -| Header (sender name) | `.cometchat-message-bubble__header` | -| Reply preview | `.cometchat-message-bubble__reply` | -| Content (incoming) | `.cometchat-message-bubble__content--incoming` | -| Content (outgoing) | `.cometchat-message-bubble__content--outgoing` | -| Footer (reactions) | `.cometchat-message-bubble__footer` | -| Status info (time + receipts) | `.cometchat-message-bubble__status-info` | -| Thread indicator | `.cometchat-message-bubble__thread` | -| Bottom (moderation) | `.cometchat-message-bubble__bottom` | +| Reply view (quoted message) | `.cometchat-message-bubble__body-reply-view` | +| Content view | `.cometchat-message-bubble__body-content-view` | +| Status info (time + receipts) | `.cometchat-message-bubble__body-status-info-view` | +| Footer (reactions) | `.cometchat-message-bubble__body-footer-view` | +| Thread indicator | `.cometchat-message-bubble__body-thread-view` | +| Bottom (moderation) | `.cometchat-message-bubble__body-bottom-view` | +| Options (context menu) | `.cometchat-message-bubble__options` | +| Incoming direction | `.cometchat-message-bubble-incoming` | +| Outgoing direction | `.cometchat-message-bubble-outgoing` | +| Action message | `.cometchat-message-bubble-action` | All class names follow BEM conventions and are stable across builds. You can target them with standard `.class-name` selectors in your CSS.