v1.2.0

Message

A chat message: the bubble, who sent it and when. Incoming at the start, outgoing at the end in brand.

Default

Incoming at the start with the sender's avatar; your own at the end, in brand.

html
MK
Did you get a chance to look at the pricing page?
10:02
Yes — the Pro card should be highlighted by default.
10:04
<div class="vt-message">
  <span class="vt-avatar vt-avatar-sm">MK</span>
  <div class="vt-message-body">
    <div class="vt-message-bubble">Did you get a chance to look at the pricing page?</div>
    <div class="vt-message-meta">10:02</div>
  </div>
</div>
<div class="vt-message vt-message-out">
  <div class="vt-message-body">
    <div class="vt-message-bubble">Yes — the Pro card should be highlighted by default.</div>
    <div class="vt-message-meta">10:04</div>
  </div>
</div>

Grouped

Messages one sender writes in a row are one vt-message with several bubbles: the avatar and the time show once.

html
MK
Agreed. I’ll add the border and the badge.
Also updated the FAQ copy, can you proofread?
10:05
Done. Two typos fixed.
Otherwise perfect.
10:12
<div class="vt-message">
  <span class="vt-avatar vt-avatar-sm">MK</span>
  <div class="vt-message-body">
    <div class="vt-message-bubble">Agreed. I’ll add the border and the badge.</div>
    <div class="vt-message-bubble">Also updated the FAQ copy, can you proofread?</div>
    <div class="vt-message-meta">10:05</div>
  </div>
</div>
<div class="vt-message vt-message-out">
  <div class="vt-message-body">
    <div class="vt-message-bubble">Done. Two typos fixed.</div>
    <div class="vt-message-bubble">Otherwise perfect.</div>
    <div class="vt-message-meta">10:12</div>
  </div>
</div>

With Author

In a group chat the meta goes above the bubbles and names the sender with vt-message-author.

html
OL
Ola Nowak 10:21
New tokens are in Figma.
LE
Leo Park 10:23
Campaign draft attached — feedback by Friday?
<div class="vt-message">
  <span class="vt-avatar vt-avatar-sm">OL</span>
  <div class="vt-message-body">
    <div class="vt-message-meta"><span class="vt-message-author">Ola Nowak</span> 10:21</div>
    <div class="vt-message-bubble">New tokens are in Figma.</div>
  </div>
</div>
<div class="vt-message">
  <span class="vt-avatar vt-avatar-sm">LE</span>
  <div class="vt-message-body">
    <div class="vt-message-meta"><span class="vt-message-author">Leo Park</span> 10:23</div>
    <div class="vt-message-bubble">Campaign draft attached — feedback by Friday?</div>
  </div>
</div>

Subtle Outgoing

In an assistant chat the brand belongs to the assistant, so the user's messages stay neutral: vt-message-subtle with vt-message-out.

html
Write a regex that validates a semver string.
<div class="vt-message vt-message-out vt-message-subtle">
  <div class="vt-message-body">
    <div class="vt-message-bubble">Write a regex that validates a semver string.</div>
  </div>
</div>

Typing

The typing indicator is a bubble holding three vt-dot vt-dot-sm, role=status with a label.

html
MK
<div class="vt-message">
  <span class="vt-avatar vt-avatar-sm">MK</span>
  <div class="vt-message-body">
    <div class="vt-message-bubble" role="status" aria-label="Maria Kim is typing">
      <span class="vt-dot vt-dot-sm vt-animate-pulse" aria-hidden="true"></span>
      <span class="vt-dot vt-dot-sm vt-animate-pulse" aria-hidden="true"></span>
      <span class="vt-dot vt-dot-sm vt-animate-pulse" aria-hidden="true"></span>
    </div>
  </div>
</div>

Guidelines

MK
On my way.
Ten minutes.
10:05
Do
Group what one sender writes in a row: one avatar, one time.
MK
On my way.
10:05
MK
Ten minutes.
10:05
Don't
Don't repeat the avatar and the time on every bubble of one burst — the thread turns into a column of faces.

Anatomy

div.vt-message(.vt-message-out)          ← One turn of the conversation
├── span.vt-avatar.vt-avatar-sm           ← Sender (incoming)
└── div.vt-message-body
    ├── div.vt-message-bubble             ← A message (one or more in a row)
    └── div.vt-message-meta               ← Time, optionally the author
        └── span.vt-message-author

API Reference

Class Type Description
vt-message Base One turn: an optional avatar and the body in a row, 8px apart; incoming — at the start of the row
vt-message-out Direction Outgoing — at the end of the row, the bubbles in brand-fill with on-brand text
vt-message-subtle Tone With vt-message-out: the outgoing bubble stays neutral (surface-subtle) — the user in an assistant chat
vt-message-body Part The bubbles and the meta stacked 4px apart; at most 80% of the row and 448px wide
vt-message-bubble Part One message — Body/SM, 8/16px padding, radius 2xl, surface-subtle
vt-message-meta Part Time (and author) — Caption, muted; under the bubbles, or above them in a group chat
vt-message-author Part Sender name inside the meta — Label/SM, secondary
vt-avatar vt-avatar-sm Part Sender avatar, first in the row; left out for your own messages

Accessibility

Feature Details
Thread The list of messages is a region the user can find (a main or a section with a label); new messages can be announced with role="log" on it
Sender The avatar image carries the sender's name in alt, or the meta names the author; direction is not told by position alone
Typing The typing bubble is role="status" with an aria-label; its dots are aria-hidden
Contrast Outgoing text is on-brand on brand-fill — the pair every theme keeps at AA