Getting started

Usage

After installing, import components and render them. Stream chat with the AI SDK or the built-in hooks, theme any subtree with one attribute, and reach for blocks when you want a whole surface.

Render

Components

tsx11 lines
import { ChatBubble, ToolCard } from "@skeehn/react";

export function Demo() {
  return (
    <>
      <ChatBubble role="user">Summarize this thread.</ChatBubble>
      <ChatBubble role="assistant">Three decisions, two open questions.</ChatBubble>
      <ToolCard name="search" status="success">3 results</ToolCard>
    </>
  );
}

Stream

With the AI SDK (recommended)

skeehn renders @ai-sdk/react messages directly — text, reasoning, tool calls and sources are mapped to the right components.

tsx8 lines
"use client";
import { useChat } from "@ai-sdk/react";
import { Conversation } from "@skeehn/react/ai";

export function Chat() {
  const { messages } = useChat();           // AI SDK v5
  return <Conversation messages={messages} />; // parts → skeehn, mapped for you
}

Prefer zero dependencies? The built-in hook works too:

tsx8 lines
"use client";
import { useChat } from "@skeehn/react/hooks"; // zero-dep, no AI SDK required
import { ChatBubble } from "@skeehn/react";

export function Chat() {
  const { messages } = useChat({ api: "/api/chat" });
  return messages.map((m) => <ChatBubble key={m.id} role={m.role}>{m.content}</ChatBubble>);
}

Compose

Blocks — whole interfaces

Drop-in surfaces from @skeehn/react/blocks: ChatConsole, AgentConsole, VoiceConsole, HeroSection.

tsx7 lines
import { ChatConsole } from "@skeehn/react/blocks";

<ChatConsole
  messages={messages}
  busy={status === "streaming"}
  onSend={(text) => sendMessage({ text })}
/>;

Theme

Re-skin any subtree

Every component reads one token contract. Change data-theme on any ancestor and the whole subtree re-skins — no rewrites.

tsx1 line
<div data-theme="terminal">{/* this subtree is green-phosphor CRT */}</div>

Next: Browse components · Blocks · Use anywhere