Bubble Chat

Stable v1.0.2

Chat bubbles for building messaging UIs, with grouped consecutive messages, safe HTML rendering, and automatic link detection so you don't have to write that parsing yourself.

Interactive Component Builder

Configure layout placement, quotes, and hover actions.

Architecture
End (Sent)
Primary
Single
Medium (md)
Metadata
Pipeline & Slots
Image
Simon Pangan
System AdminWhat time is the meeting tomorrow?
Click or Long Press on this bubble to trigger custom events! https://vuejs.org
10:42 AM
Component Code
<BubbleChat
  placement="end"
  variant="primary"
  sender="Simon Pangan"
  time="10:42 AM"
  avatar="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS-pEvonrkLzJKKFg5xc5KKX2XuNfkIApZK2w&s"
  @longpress="menuOpen = true"
>
  <template #reply>
    <span class="font-bold">Simon Pangan</span>
    <span class="truncate">What time is the meeting?</span>
  </template>
  <template #actions>
    <Button icon="lucide:smile" variant="text" size="xs" />

    <!-- Only the 3-dot button opens the menu, not the whole bubble -->
    <Popover v-model="menuOpen" placement="left-start" widthClass="w-max">
      <template #trigger>
        <Button icon="lucide:more-vertical" variant="text" size="xs" />
      </template>

      <div class="flex flex-col gap-1 p-1 min-w-32">
        <Button icon="lucide:copy" label="Copy Text" variant="text" class="justify-start" />
        <Button icon="lucide:reply" label="Reply" variant="text" class="justify-start" />
      </div>
    </Popover>
  </template>
  Click or Long Press on this bubble to trigger custom events! https://vuejs.org
</BubbleChat>

Messenger Layout Pattern

Desktop: Hover messages for quick actions, or click them.
Mobile/Touch: Tap or Long Press messages to reveal the context menu.

October 24, 2026
Image
Pre pa send na ng link!
11:00 AM
Image
Simon PanganCan you send me the UI spec?
11:05 AM
Structural Layout
<div class="flex flex-col h-[600px] border border-main rounded-2xl bg-content">
  <Toolbar variant="flat" class="border-b border-main shrink-0">
    </Toolbar>

  <div class="flex-1 overflow-y-auto p-4 flex flex-col gap-2">
    <template v-for="msg in messages" :key="msg.id">

      <BubbleChat
        :content="msg.text"
        :placement="msg.isMe ? 'end' : 'start'"
        :variant="msg.isMe ? 'primary' : 'surface'"
        @longpress="msg.showMenu = true"
        @contextmenu.prevent="msg.showMenu = true"
      >
        <template #actions>
           <Button icon="lucide:smile" />

           <!-- Only the 3-dot button opens the menu, not the whole bubble -->
           <Popover v-model="msg.showMenu" :placement="msg.isMe ? 'left-start' : 'right-start'">
             <template #trigger>
               <Button icon="lucide:more-vertical" />
             </template>

             <div class="flex flex-col gap-1 p-1">
               <Button label="Copy" variant="text" />
               <Button label="Reply" variant="text" />
               <Button label="Delete" variant="text" severity="danger" />
             </div>
           </Popover>
        </template>
        <template v-if="msg.isMe" #status>
           <Icon icon="lucide:check" />
        </template>
      </BubbleChat>

    </template>
  </div>

  <Toolbar variant="flat" class="border-t border-main shrink-0">
    <InputText v-model="chatInput" class="rounded-full w-full" />
    <Button icon="lucide:send-horizontal" variant="text" />
  </Toolbar>
</div>

API Reference

Props & Events
Prop / Event
Type
Default
Description
content
string
undefined
Message content (safely parses HTML and Auto-links).
parseHtml
boolean
true
Safely allows basic bold/italic tags while blocking scripts.
autoLink
boolean
true
Converts URLs in content to clickable anchor tags.
blockLinks
boolean
false
Strips URLs and replaces them with a high-visibility Danger badge.
placement
"start" | "end"
"start"
Bubble alignment.
groupPosition
"first" | "middle" | "last" | "single"
"single"
Tail logic for consecutive messages.
variant
string
"surface"
Color themes.
size
"xs" | "sm" | "md" | "lg" | "xl"
"md"
Padding and text scaling.
time
string
undefined
Timestamp displayed in the footer area.
sender
string
undefined
Name displayed above the bubble.
avatar
string
undefined
Avatar URL passed to the internal Image component.
showAvatar
boolean
true
Toggles avatar visibility and placeholder spacing.
@click
Event
-
Native mouse click or short touch tap.
@dblclick
Event
-
Native double mouse click.
@longpress
Event
-
Fires when the bubble is held down for 500ms (Mouse or Touch).
Slots
Slot Name
Target Data
Description
default
Any
Message content (bypasses security engine).
reply
Slot
Quoted message block that dynamically inherits current text color.
actions
Slot
Hidden action bar that appears smoothly on hover (desktop).
status
Slot
Icon area next to the timestamp for read receipts.
avatar
Slot
Override the default Image component.