Skip to content

ChatBubble

A chat UI component supporting three message role variants. Bold-bordered bubbles with shadow offsets give the conversation interface a distinctive personality.

Demo

Preview
对话开始于 2025-06-01
AL
Alex
嘿!这个新粗野主义 UI 库看起来太赞了!
14:01
对吧!粗边框 + 硬朗阴影,直接把普通组件卷死。
14:02
AL
Alex
Kanban + TreeView 这两个复合组件是重头戏 🔥
14:03
还有 Carousel!Embla 驱动的,性能拉满 💪
14:03

颜色(仅 sent 生效)

AL
Alex
received 不受 color 影响
14:00
default 配色
14:01
primary 配色
14:02
accent 配色
14:03

尺寸

sm 小号气泡
14:00
default 默认气泡
14:01
lg 大号气泡
14:02

Installation

pnpm dlx brutx-vue@latest add chat-bubble

Usage

vue
<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.

vue
<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

VariantStylePurpose
receivedLeft-aligned, background colorMessages from others
sentRight-aligned, primary color backgroundMessages sent by yourself
systemCentered, italic, dashed border, no shadow, forced text-xsSystem notifications

Note: The system variant ignores the size prop and always uses text-xs. It also hides the avatar and sender name.

Colors

ColorDescription
defaultDefault color scheme; sent bubbles use primary color (brutal-primary) background
primaryPrimary color scheme; sent bubbles use primary color (brutal-primary) background with primary color shadow (shadow-brutal-primary)
accentAccent color scheme; sent bubbles use accent color (brutal-accent) background

Sizes

The size prop controls bubble padding, text size, and avatar dimensions simultaneously.

SizeBubble PaddingText SizeAvatar Size
smpx-3 py-1.5text-xsw-6 h-6
defaultpx-4 py-2.5text-smw-8 h-8
lgpx-5 py-3.5text-basew-10 h-10
vue
<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:

vue
<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

ts
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

ts
type MessageStatus = 'sending' | 'sent' | 'delivered' | 'read' | 'failed'
StatusIconStyle
sendingSpinning loader iconSemi-transparent + rotation animation
sentSingle checkSemi-transparent
deliveredDouble checkSlightly darker
readDouble checkTheme primary color
failedWarning iconDestructive color

Props

ChatBubble

PropTypeDefaultDescription
messageChatMessageMessage data object (required)
color'default' | 'primary' | 'accent''default'Background color scheme for sent bubbles; only effective for variant="sent", received/system are unaffected
size'sm' | 'default' | 'lg''default'Bubble padding/text size, also adjusts avatar size
showAvatarbooleantrueWhether to show the avatar area (system messages always hidden)
showStatusbooleantrueWhether to show the message status icon (sent messages only)
showTimestampbooleantrueWhether to show the timestamp
dateFormat(date: Date) => stringCustom date formatting function; uses Date.toLocaleString() when unset
classstringCustom CSS class for the bubble

ChatContainer

PropTypeDefaultDescription
messagesChatMessage[]Message array (required)
groupByTimebooleanfalseWhether to group by time (today/yesterday/date)
groupIntervalnumber5Time grouping interval (minutes) within the same date; adjacent messages exceeding this gap are split into a new group
showAvatarbooleantrueWhether to show avatars
showStatusbooleantrueWhether to show message status
showTimestampbooleantrueWhether to show timestamps
dateFormat(date: Date) => stringCustom date formatting function
classstringCustom CSS class

Note: When groupByTime is true, messages are automatically grouped by date labels (today/yesterday/specific date), with dividers and date labels between groups; within the same date, adjacent messages whose time gap exceeds groupInterval minutes are further split into separate groups (showing only the group spacing, without repeating the date label).

Slots

SlotScopeDescription
defaultCustom bubble content (defaults to displaying message.content)

Accessibility

  • ARIA Attributes: ChatContainer uses role="log" for accessibility support
  • Semantics: Message bubbles use semantic structure, supporting correct screen reader narration

Brute force builds.