Skip to content

Bubble

Menampilkan isi percakapan dalam gelembung pesan. Mendukung varian, perataan, pengelompokan, reaksi, dan konten yang bisa dilipat.

Hey there! what's up?
Hey! Want to see chat bubbles?
I can group messages, switch sides, and keep the whole thread easy to scan.
Sure. Hit me with your best demo.
Yes. You are reading a demo that is demoing itself. Very meta. Very on-brand.

Komponen Bubble menampilkan isi percakapan dalam bingkai. Cocok untuk teks chat, keluaran terstruktur singkat, balasan berkutip, saran, dan reaksi.

Untuk antarmuka chat yang lengkap, pakai komponen Message. Bubble memang sengaja dibatasi pada badan gelembungnya saja. Avatar, nama, waktu, metadata, dan aksi tingkat pesan diletakkan di Message.

Instalasi

CLI

bash
npx shadcn-vue@latest add bubble

Manual

Salin dan tempel kode sumber di GitHub ke project Anda.

Sesuaikan path import dengan struktur project Anda.

Penggunaan

vue
<script setup lang="ts">
import { Bubble, BubbleContent, BubbleReactions } from '@/components/ui/bubble'
</script>

<template>
  <Bubble>
    <BubbleContent>
      I checked the registry output and removed the stale route.
    </BubbleContent>
    <BubbleReactions>
      <span>👍</span>
    </BubbleReactions>
  </Bubble>
</template>

Komposisi

Susunan berikut adalah cara membangun sebuah bubble:

text
Bubble
├── BubbleContent
└── BubbleReactions

Pakai BubbleGroup untuk mengelompokkan bubble berurutan dari pengirim yang sama:

text
BubbleGroup
├── Bubble
│   └── BubbleContent
└── Bubble
    └── BubbleContent

Fitur

  • Tujuh varian tampilan, dari bubble primary yang tegas sampai konten ghost tanpa bingkai.
  • Perataan awal dan akhir untuk bubble pengirim dan penerima.
  • Reaksi yang menempel di tepi bubble, dengan sisi dan perataan yang bisa diatur.
  • Ukuran bubble menyesuaikan isinya, maksimal 80% dari lebar container.
  • Konten polimorfik lewat as atau as-child untuk bubble berupa tautan dan tombol.
  • Style tiap bagian bisa disesuaikan lewat prop class.

Contoh

Varian

Pakai variant untuk mengubah tampilan bubble.

This is the default primary bubble.
This is the secondary variant.
This one is muted. It uses a lower emphasis color for the chat bubble.
This one is tinted. The tint is a softer color derived from the primary color.
We can also use an outlined variant.
Or a destructive variant with a reaction.
Ghost bubbles work for assistant text, markdown, and other content that should not be framed. This is perfect for assistant messages that should not have a frame and can take the full width of the container. You can also render code in it. Ghost bubbles are full width and can take the full width of the container.
VariantDescription
defaultA strong primary bubble, usually for the current user.
secondaryThe standard neutral bubble for conversation content.
mutedA lower-emphasis bubble for quiet supporting content.
tintedA subtle primary-tinted bubble.
outlineA bordered bubble for secondary or rich content.
ghostUnframed content for assistant text or rich content.
destructiveA destructive bubble for error or failed actions.

Ukuran bubble menyesuaikan isinya, maksimal 80% dari lebar container. Varian ghost melepas batas lebar itu, sehingga teks asisten dan konten kaya bisa memenuhi satu baris penuh.

Perataan

Pakai align pada Bubble untuk menaruhnya di sisi awal atau akhir percakapan.

This bubble is aligned to the start. This is the default alignment.
This bubble is aligned to the end. Use this for user messages.
alignDescription
startAlign the bubble to the start of the conversation.
endAlign the bubble to the end of the conversation.

Catatan: saat membangun antarmuka chat, align biasanya lebih tepat diatur di komponen Message. Bubble di dalam MessageContent otomatis mengikuti perataan pesannya.

Bubble Group

Pakai BubbleGroup untuk mengelompokkan bubble berurutan dari pengirim yang sama. Perlu dicatat, prop align diatur pada komponen Bubble, bukan pada BubbleGroup.

text
BubbleGroup
├── Bubble
│   └── BubbleContent
└── Bubble
    └── BubbleContent
Can you tell me what's the issue?
You tell me!
It worked yesterday. You broke it!
Find the bug and fix it.
👀
Want me to diff yesterday's you against today's you? It's a bit embarrassing.

Tautan dan Tombol

Pakai as-child untuk menggabungkan style dan atribut BubbleContent ke tautan atau tombol yang Anda taruh di slot bawaannya.

How can I help you today?
vue
<script setup lang="ts">
import { Bubble, BubbleContent } from '@/components/ui/bubble'
</script>

<template>
  <Bubble variant="muted">
    <BubbleContent as-child>
      <button type="button">Click here</button>
    </BubbleContent>
  </Bubble>
</template>

Reactions

Pakai BubbleReactions untuk menampilkan reaksi pada bubble, atau tombol aksi cepat. Posisinya diatur lewat side dan alignside="top" menempelkannya di tepi atas. Karena reaksi menumpuk di tepi bubble, sisakan jarak vertikal antar baris; contoh di bawah memakai gap yang lebih besar untuk alasan itu.

I don't need tests, I know my code works.
Bold. Fine I'll add some tests. I'll let you know when they're done.
Tests passed on the first try. All 142 of them. Looking good!
Are you sure I can run this command?

Tampilkan Selengkapnya

Isi bubble yang panjang bisa dipadukan dengan Collapsible agar bisa dibuka dan ditutup. Pakai komponen CollapsibleTrigger sebagai pemicunya.

How can I help you today?
The accessibility review found two focus states that were visually too subtle in dark mode. I checked the dialog, menu, and drawer paths because each one renders focusable control...

Tooltip

Bungkus bubble dengan Tooltip untuk memunculkan metadata saat di-hover, misalnya kapan pesan itu dibaca.

Did you remove the stale route?
Yes, removed it from the registry.

Popover

Padukan bubble dengan Popover untuk memunculkan keterangan tambahan saat diminta, misalnya pesan error lengkap dari aksi yang gagal.

Run the build script.
Failed to run the command.

Aksesibilitas

Bubble hanya menampilkan badan pesannya. Makna di tingkat percakapan sebaiknya tetap dipegang container di sekelilingnya. Ikuti panduan di bawah ini.

Memberi Label pada Reaksi

Reaksi ditampilkan sebagai deretan emoji. Pembaca layar membacakan tiap emoji tanpa konteks, dan penghitung seperti +8 dibaca sebagai "plus delapan". Jadikan deretan itu satu gambar utuh dengan aria-label yang jelas supaya dibacakan sekali saja. role="img" sekaligus menyembunyikan emoji satu per satu dari teknologi bantu, jadi aria-hidden tidak diperlukan.

vue
<BubbleReactions role="img" aria-label="Reactions: thumbs up, fire, and 8 more">
  <span>👍</span>
  <span>🔥</span>
  <span>+8</span>
</BubbleReactions>

Kalau reaksinya bisa diklik, tampilkan sebagai tombol, dan beri aria-label pada tombol yang hanya berupa ikon.

vue
<BubbleReactions>
  <Button aria-label="Thumbs up" variant="secondary" size="icon-xs">
    <ThumbsUpIcon />
  </Button>
</BubbleReactions>

Bubble yang Interaktif

Kalau bubble bisa diklik, teruskan elemen <button> atau <a> sungguhan lewat BubbleContent dengan as-child, supaya bisa di-focus dan punya role yang benar. BubbleContent sudah menyediakan cincin focus yang terlihat untuk elemen interaktif, dan nama aksesibelnya diambil dari teks bubble — tidak perlu label tambahan.

vue
<Bubble variant="muted" align="end">
  <BubbleContent as-child>
    <button type="button" @click="onReply">
      I forgot my password
    </button>
  </BubbleContent>
</Bubble>

Makna yang Tidak Bergantung Warna

Varian bubble menandakan peran dan nada lewat warna. Padukan dengan teks, perataan, atau ikon supaya maknanya tidak bergantung pada warna semata. Untuk bubble destructive, jelaskan konteks error-nya di dalam teks pesan, bukan mengandalkan warnanya.

Referensi API

Semua bagian Bubble menghasilkan <div> secara bawaan. Pakai as untuk memilih elemen lain, atau as-child untuk menggabungkan atribut dan style komponen ke satu elemen atau komponen di dalam slot bawaannya.

Bubble

Pembungkus terluar bubble.

PropTypeDefaultDescription
variant"default" | "secondary" | "muted" | "tinted" | "outline" | "ghost" | "destructive""default"The bubble visual treatment.
align"start" | "end""start"The inline alignment of the bubble.
asstring | Component"div"The element or component to render.
as-childbooleanfalseRender the default slot as the root and merge props onto it.
classstring-Additional classes to apply to the root element.

BubbleContent

Pembungkus isi bubble.

PropTypeDefaultDescription
asstring | Component"div"The element or component to render.
as-childbooleanfalseRender the default slot as the root and merge props onto it.
classstring-Additional classes to apply to the content element.

BubbleReactions

Menampilkan reaksi yang menumpuk di tepi bubble.

PropTypeDefaultDescription
side"top" | "bottom""bottom"The side of the bubble to anchor the reactions.
align"start" | "end""end"The inline alignment of the reactions.
asstring | Component"div"The element or component to render.
as-childbooleanfalseRender the default slot as the root and merge props onto it.
classstring-Additional classes to apply to the reaction row.

BubbleGroup

Mengelompokkan bubble berurutan dari pengirim yang sama.

PropTypeDefaultDescription
asstring | Component"div"The element or component to render.
as-childbooleanfalseRender the default slot as the root and merge props onto it.
classstring-Additional classes to apply to the group root.

Dirilis di bawah lisensi MIT. Fork dari shadcn-vue.