Components
Chat
Conversation primitives: message scroller, messages, bubbles, attachments, and markers.
Conversation
-> shows as two glyphs.
calt substitutions for arrows.
same glyphs on both sides. Thanks.
<div class="max-h-80 overflow-y-auto rounded-xl border border-separator bg-bg-surface p-4">
{/* marker */}
<div class="flex items-center gap-3">
<span class="h-px flex-1 bg-separator" />
<span class="rounded-full border border-separator px-2.5 py-0.5 text-xs text-text-tertiary">Today</span>
<span class="h-px flex-1 bg-separator" />
</div>
{/* received */}
<div class="mt-4 flex items-end gap-2">
<span class="flex size-7 items-center justify-center rounded-full bg-bg-elevated font-mono text-[11px]">mk</span>
<div class="max-w-[75%] rounded-lg rounded-bl-sm bg-bg-elevated px-3 py-2 text-sm">…</div>
</div>
{/* sent */}
<div class="mt-3 flex justify-end">
<div class="max-w-[75%] rounded-lg rounded-br-sm bg-primary px-3 py-2 text-sm text-white">…</div>
</div>
</div> Attachment
Full write-up, in case anyone else hits this.
ligatures-deep-dive.md 12 KBJump to latest
Thread states
marta
andrés
marta
Markers
Markers label a point in the thread. Variants (divider vs inline pill),
status dot, with icon, shimmer while pending
(animate-pulse), a bordered style, and
links and buttons inside the marker.
Attachments
Image thumbnail and file chips, upload states (uploading, error), two sizes (row one default, row two small), a group with an overflow count, and the trigger button that opens the file picker.
Message anatomy
Messages carry a header and footer (name, time, "edited · seen"), hover actions, bubble reactions, and a show more control for long content. On hover the timestamp shows as a tooltip, and the action button opens a popover menu of more options.
In the real pattern the scroller anchors to the newest message and only shows the “Latest” pill once the reader has scrolled up; clicking it snaps back to the bottom.
The message scroller also handles anchoring turns (each user turn pins to the top as its reply streams in), keeping context visible (the prompt stays on screen while the answer grows), opening saved threads (restore scroll to the last-read message), animating new messages, jumping to messages by id, reading scroll state (at-bottom / has-unread) to drive the Latest pill, and virtualization so long histories render only the visible window.
Markdown for agents: /design/chat.md · spec: /design.md