Working with the components directly
The kai-* elements are the fast path. When you want full control over markup and layout — and you’re in a Solid app — skip the wrapper and import the underlying pieces from @kitn.ai/ui. You compose them in JSX, and your bundler tree-shakes away whatever you don’t use.
This page is the catalog, organized by the four layers. For a full streaming chat built this way, see the Solid guide.
npm install @kitn.ai/ui solid-jsimport '@kitn.ai/ui/theme.css'; // design tokens, once near your entryHeadless primitives
Section titled “Headless primitives”Behavior with no markup — the logic you’d otherwise rewrite per app. These are the layer the kai-* elements don’t expose, so importing them directly is the main reason to drop down here.
import { useTextStream, useStickToBottom, useAutoResize, useVoiceRecorder,} from '@kitn.ai/ui';useTextStream— drive token-by-token streaming into your own UI.useStickToBottom— keep a scroll container pinned to the latest message, yielding when the reader scrolls up.useAutoResize— grow a textarea with its content.useVoiceRecorder— microphone capture state for a voice composer.
ChatConfig (and its useChatConfig hook) sets shared options like prose size for everything rendered inside it.
UI primitives
Section titled “UI primitives”The kit’s own accessible building blocks. Useful on their own, well outside a chat.
import { Button, Switch, Avatar, Badge, Separator } from '@kitn.ai/ui';import { Tooltip, HoverCard, Dropdown } from '@kitn.ai/ui';import { Resizable, ResizablePanel, ScrollArea } from '@kitn.ai/ui';
<Switch label="Temporary chat" onChange={(on) => setTemporary(on)} /><Button variant="ghost" size="icon" aria-label="Add"><PlusIcon /></Button> {/* your icon */}Resizable + ResizablePanel build a draggable split — handles drop in automatically between visible panels. See the Solid guide for a full sidebar-plus-chat layout.
Feature components
Section titled “Feature components”The AI surface. Compose a thread, or drop a single component anywhere.
import { ChatContainer, ChatContainerContent, Message, MessageContent, PromptInput, PromptInputTextarea, PromptInputActions,} from '@kitn.ai/ui';Each one also works standalone — render just the part you need:
import { Markdown, Reasoning, ReasoningTrigger, ReasoningContent, Tool, Artifact,} from '@kitn.ai/ui';
<Markdown content={assistantReply} /><Reasoning isStreaming={isStreaming}> <ReasoningTrigger>View reasoning</ReasoningTrigger> <ReasoningContent markdown>{thinkingText}</ReasoningContent></Reasoning><Tool toolPart={toolCall} defaultOpen /><Artifact files={artifactFiles} />Reasoning is a compound: pair it with ReasoningTrigger and ReasoningContent. Prose size for Markdown comes from the surrounding ChatConfig, not a prop.
ChatContainer is transport-agnostic: it owns the conversation UI, you own the request. Render messages inside ChatContainerContent and stream the reply into your signal from PromptInput’s onSubmit.
Mix the two
Section titled “Mix the two”Native components and kai-* elements ship in the same package and coexist. Compose primitives where you want control, and drop a <kai-chat> shell where you want batteries included — even on different screens of the same app.
- Run the kit locally — the build and Storybook dev loop.
- Create or modify a component — add your own primitive and element.