ChatBubble
A chat UI component supporting three message role variants. Bold-bordered bubbles with shadow offsets give the conversation interface a distinctive personality.
Demo
颜色(仅 sent 生效)
尺寸
Installation
pnpm dlx brutx-vue@latest add chat-bubbleUsage
<script setup>
import { ChatBubble } from 'brutx-ui-vue'
const message = {
id: '1',
variant: 'received',
name: 'Alex',
content: 'This UI library is amazing!',
timestamp: '14:01',
}
</script>
<template>
<div class="flex flex-col gap-3">
<ChatBubble :message="{ id: '1', variant: 'received', name: 'Alex', content: 'Hello!' }" />
<ChatBubble :message="{ id: '2', variant: 'sent', content: 'Hey!' }" />
<ChatBubble :message="{ id: '3', variant: 'system', content: 'Conversation started' }" />
</div>
</template>Color Variants
The color prop switches the background color scheme for variant="sent" bubbles, combining orthogonally with variant (e.g., variant="sent" color="accent"). received and system bubbles are not affected by color.
<script setup>
import { ChatBubble } from 'brutx-ui-vue'
</script>
<template>
<div class="flex flex-col gap-3">
<ChatBubble :message="{ id: '1', variant: 'sent', content: 'Default color', timestamp: '14:00' }" color="default" />
<ChatBubble :message="{ id: '2', variant: 'sent', content: 'Primary color', timestamp: '14:01' }" color="primary" />
<ChatBubble :message="{ id: '3', variant: 'sent', content: 'Accent color', timestamp: '14:02' }" color="accent" />
</div>
</template>Variants
Message Roles
| Variant | Style | Purpose |
|---|---|---|
received | Left-aligned, background color | Messages from others |
sent | Right-aligned, primary color background | Messages sent by yourself |
system | Centered, italic, dashed border, no shadow, forced text-xs | System notifications |
Note: The
systemvariant ignores thesizeprop and always usestext-xs. It also hides the avatar and sender name.
Colors
| Color | Description |
|---|---|
default | Default color scheme; sent bubbles use primary color (brutal-primary) background |
primary | Primary color scheme; sent bubbles use primary color (brutal-primary) background with primary color shadow (shadow-brutal-primary) |
accent | Accent color scheme; sent bubbles use accent color (brutal-accent) background |
Sizes
The size prop controls bubble padding, text size, and avatar dimensions simultaneously.
| Size | Bubble Padding | Text Size | Avatar Size |
|---|---|---|---|
sm | px-3 py-1.5 | text-xs | w-6 h-6 |
default | px-4 py-2.5 | text-sm | w-8 h-8 |
lg | px-5 py-3.5 | text-base | w-10 h-10 |
<script setup>
import { ChatBubble } from 'brutx-ui-vue'
</script>
<template>
<div class="flex flex-col gap-3">
<ChatBubble :message="{ id: '1', variant: 'sent', name: 'Me', content: 'Small bubble', timestamp: '14:00' }" size="sm" />
<ChatBubble :message="{ id: '2', variant: 'sent', name: 'Me', content: 'Default bubble', timestamp: '14:01' }" size="default" />
<ChatBubble :message="{ id: '3', variant: 'sent', name: 'Me', content: 'Large bubble', timestamp: '14:02' }" size="lg" />
</div>
</template>Sub-components
ChatContainer
A chat message container with time-based grouping support:
<script setup>
import { ChatContainer } from 'brutx-ui-vue'
const messages = [
{ id: '1', variant: 'received', name: 'Alex', content: 'Hello!', timestamp: new Date() },
{ id: '2', variant: 'sent', content: 'Hey!', timestamp: new Date(), status: 'read' },
]
</script>
<template>
<ChatContainer :messages="messages" group-by-time show-status />
</template>Data Types
ChatMessage
interface ChatMessage {
id: string // Unique message identifier (required)
content: string // Message text content (required)
variant?: 'sent' | 'received' | 'system' // Message variant, defaults to 'received'
avatar?: string // Avatar image URL; falls back to initials on load failure
name?: string // Sender name, used for display and initial generation
timestamp?: string | Date // Timestamp; strings are displayed directly, Date objects are formatted via dateFormat or toLocaleString
status?: MessageStatus // Message status, only effective for variant="sent"
}MessageStatus
type MessageStatus = 'sending' | 'sent' | 'delivered' | 'read' | 'failed'| Status | Icon | Style |
|---|---|---|
sending | Spinning loader icon | Semi-transparent + rotation animation |
sent | Single check | Semi-transparent |
delivered | Double check | Slightly darker |
read | Double check | Theme primary color |
failed | Warning icon | Destructive color |
Note:
statusis a closed union type at the type level, but message data usually comes from backend APIs and may carry values outside the enum at runtime; in that case ChatBubble silently ignores the status (no status icon is rendered) without throwing an error.
API Reference
ChatBubble
| Name | Type | Default | Description |
|---|---|---|---|
messageRequired | ChatMessage | — | The chat message to display, including its id, content, role, timestamp, and optional avatar and status data. |
DetailsDeclared typeChatMessage Referenced types ChatMessage Type definition — ChatMessageexport interface ChatMessage {
id: string
content: string
/** 消息角色,默认 'received' */
variant?: 'sent' | 'received' | 'system'
/** 头像图片 URL;加载失败时回退为首字母缩写 */
avatar?: string
/** 发送者姓名,用于展示名称与生成首字母缩写 */
name?: string
/**
* 时间戳。
* - `string`:按原样直接展示(不做格式化,传入方负责提供展示格式);
* - `Date`:按 `dateFormat` 或 `toLocaleString` 格式化。
*/
timestamp?: string | Date
/**
* 消息状态,**仅对 `variant === 'sent'` 生效**;received/system 携带时会被静默忽略。
*/
status?: MessageStatus
}Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatBubble.vue | |||
color | "accent" | "default" | "primary" | undefined | "default" | Sets the color of sent-role bubbles; received and system roles are unaffected. |
DetailsDeclared typeNonNullable<"default" | "primary" | "accent" | null | undefined> | undefined Literal values
Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatBubble.vue | |||
size | "default" | "lg" | "sm" | undefined | "default" | Sets bubble padding and text size and adjusts the avatar size to match. |
DetailsDeclared typeNonNullable<"default" | "lg" | "sm" | null | undefined> | undefined Literal values
Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatBubble.vue | |||
showAvatar | boolean | undefined | true | Controls the avatar area; system-role messages never display an avatar. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatBubble.vue | |||
showStatus | boolean | undefined | true | Controls the send-status icon; the status icon is used only for sent-role messages. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatBubble.vue | |||
showTimestamp | boolean | undefined | true | Controls whether the message timestamp is displayed. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatBubble.vue | |||
dateFormat | ((date: Date) => string) | undefined | undefined | Custom formatter for the message date and time; Date.toLocaleString is used when omitted. |
DetailsDeclared type((date: Date) => string) | undefined Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatBubble.vue | |||
class | string | undefined | undefined | Custom CSS classes added to the message bubble root element. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatBubble.vue | |||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | Replaces the message body; message.content is shown when omitted. |
DetailsDeclared type{}Sourcepackages/ui/src/components/chat-bubble/ChatBubble.vue | ||
ChatContainer
| Name | Type | Default | Description |
|---|---|---|---|
messagesRequired | ChatMessage[] | — | The ordered array of chat messages to display. |
DetailsDeclared typeChatMessage[] Referenced types ChatMessage Type definition — ChatMessageexport interface ChatMessage {
id: string
content: string
/** 消息角色,默认 'received' */
variant?: 'sent' | 'received' | 'system'
/** 头像图片 URL;加载失败时回退为首字母缩写 */
avatar?: string
/** 发送者姓名,用于展示名称与生成首字母缩写 */
name?: string
/**
* 时间戳。
* - `string`:按原样直接展示(不做格式化,传入方负责提供展示格式);
* - `Date`:按 `dateFormat` 或 `toLocaleString` 格式化。
*/
timestamp?: string | Date
/**
* 消息状态,**仅对 `variant === 'sent'` 生效**;received/system 携带时会被静默忽略。
*/
status?: MessageStatus
}Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatContainer.vue | |||
groupByTime | boolean | undefined | false | Groups messages by calendar date and time interval and displays date or time separators.
|
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatContainer.vue | |||
groupInterval | number | undefined | 5 | The maximum gap between adjacent messages in one time group, in minutes; values below 1 are clamped to 1. |
DetailsDeclared typenumber | undefined Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatContainer.vue | |||
showAvatar | boolean | undefined | true | Controls whether message avatar areas are displayed. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatContainer.vue | |||
showStatus | boolean | undefined | true | Controls whether status icons are displayed for sent messages. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatContainer.vue | |||
showTimestamp | boolean | undefined | true | Controls whether message timestamps are displayed. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatContainer.vue | |||
dateFormat | ((date: Date) => string) | undefined | undefined | Formats message times and grouping labels; local date and time formatting is used when omitted. |
DetailsDeclared type((date: Date) => string) | undefined Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatContainer.vue | |||
class | string | undefined | undefined | Custom CSS classes added to the chat container root element. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/chat-bubble/ChatContainer.vue | |||
Note: When
groupByTimeistrue:
- Messages with a valid timestamp are sorted by timestamp ascending, so unordered input still yields continuous, non-jumping date groups; messages without a valid timestamp (missing, or display-only strings like
'14:30','yesterday'that cannot be parsed) stay anchored at their original index — they do not sink to the end and keep their relative order;- Group boundaries are compared by the real calendar date (year/month/day), decoupled from the display string produced by
dateFormat: even if a custom format outputs a time-only dimension (e.g., HH:mm), messages from different days are never merged and same-day messages are never split into separate date groups;- Groups are separated by dividers and date labels (today/yesterday/specific date);
- Within the same date, adjacent messages whose time gap exceeds
groupIntervalminutes are further split into separate groups that show the specific time (HH:mm, customizable viadateFormat), without repeating the date label.
Accessibility
- ARIA Attributes: ChatContainer uses
role="log"for accessibility support - Semantics: Message bubbles use semantic structure, supporting correct screen reader narration