Component

Chat

A full chat UI with conversations and reply-threads. Backend-agnostic — the wire is a ChatTransport you supply (SSE / WebSocket / fetch); nothing about your backend leaks into the UI. Two threading modes, reactions, edit/delete, streaming, and rich content (markdown, code, gifs) via the headless @refraction-ui/conversation core.

Examples

Toggle the threading mode and send a message to see streaming, markdown/code/gif rendering, reactions, and the thread panel.

Rendering rich content
5:55 PMYou

How do I render markdown, code, and gifs in a message?

A
Assistant5:56 PM

Messages are markdown, so you get code fences:

function add(a, b) { return a + b }
5:57 PMYou

Perfect — and this is a reply in the thread.

Type a message to watch the mock transport stream a reply. In inline mode, replies quote their parent and open the thread panel; in panel mode, only roots show with a “N replies” opener.

Installation

$pnpm add @refraction-ui/react

Usage

tsx
import { useConversation, Chat, type ChatTransport } from '@refraction-ui/react-conversation'

// Your backend, behind the transport contract — nothing else knows about it:
const transport: ChatTransport = {
  name: 'my-api',
  async *send({ message, history, signal }) {
    const res = await fetch('/api/chat', {
      method: 'POST',
      body: JSON.stringify({ message, history }),
      signal,
    })
    const reader = res.body!.getReader()
    const dec = new TextDecoder()
    for (;;) {
      const { value, done } = await reader.read()
      if (done) break
      yield { delta: dec.decode(value) } // streams token-by-token into the UI
    }
  },
}

export function MyChat() {
  const conversation = useConversation({ transport })
  return <Chat conversation={conversation} />
}

Props

PropTypeDefaultDescription
conversationUseConversationResult--The store + bound actions returned by useConversation().
showConversationListboolean--Show the conversation-list sidebar. Default true.
showModeToggleboolean--Show the inline/panel threading toggle in the header. Default true.
placeholderstring--Composer placeholder text.
currentUserIdstring--Local user id — controls which messages are editable/deletable.
emptyStateReactNode--Rendered when the active conversation has no messages.
classNamestring--Additional CSS classes.