Components

Chat Widget

A controlled React chat widget with streaming Markdown, tool activity, approval cards, localized labels, and responsive dialog layouts.

Install
Add this registry item to your app with shadcn.
bash
bunx --bun shadcn@latest add https://krakstack.net/r/chat-widget.json

Overview

chat-widget installs a controlled assistant dialog and a transport-neutral event reducer. It renders streaming Markdown, tool progress, tool descriptions, approval cards, errors, and responsive minimized or maximized layouts. English and French labels are built in and every label can be overridden.

Install

bash
bunx shadcn@latest add @krak-stack/chat-widget

The widget installs chat-service automatically and creates components/ui/chat-widget.tsx plus services/chat/state.ts. Add TooltipProvider near your application root if it is not already present.

tsx
<TooltipProvider> <RouterProvider router={router} /> </TooltipProvider>

Controlled Setup

The widget does not own a network client. Keep ChatState in Effect Atom, React state, TanStack Query, or another store and implement the four callbacks.

tsx
const [state, setState] = useState(initialChatState); const controller = new AbortController(); const submit = async (action: ChatSubmitAction) => { setState((current) => ({ ...current, pending: true, error: undefined })); for await (const event of streamChat({ action, history: state.history, signal: controller.signal, })) { setState((current) => reduceChatEvent(current, event)); } setState((current) => ({ ...current, pending: false })); }; <ChatWidget state={state} onSubmit={submit} onInterrupt={() => controller.abort()} onReset={() => setState(initialChatState)} />;

Use a fresh abort controller for each request in production. Add the user message optimistically before starting the stream; the reducer owns assistant messages and tool state emitted by the server.

Event Reduction

Call reduceChatEvent(current, event) for every decoded ChatEvent. The reducer appends text deltas, stores serialized history, updates tool completion, exposes approval requests, and removes empty assistant placeholders after errors.

Approval Actions

When a tool asks for approval, the widget calls onSubmit with approvalId, toolCallId, and the user's decision. Forward approvalId and approved to the server together with the latest history. toolCallId is client-side correlation data.

Messages

The widget selects English or French through Paraglide's current locale and accepts partial overrides.

tsx
<ChatWidget {...props} messages={{ title: "Support Assistant", description: "Ask about billing, projects, or account access.", placeholder: "How can we help?", }} />

Exported chatWidgetMessages(locale, overrides) can also resolve labels for tests or surrounding UI.

Preview