@kitn.ai/chat
Version:
Framework-agnostic, Shadow-DOM web components for building AI chat interfaces — works in React, Vue, Angular, Svelte, or plain HTML. Authored in SolidJS.
174 lines (137 loc) • 6.68 kB
text/mdx
import { Meta } from '@storybook/addon-docs/blocks';
<Meta title="Docs/Frameworks/Solid" />
# Solid
The kit is **authored in SolidJS** — the `<kc-*>` web components are compiled from these very
components. So Solid devs get the richest path of any framework, with **two ways to build** that
you can freely mix:
1. **Native SolidJS components** (`.ai/chat`) — `ChatContainer`, `Message`, `PromptInput`, and
the rest, composed in your own JSX. Full compositional control and the smallest output for a
Solid app. **This is the recommended Solid path.**
2. The same framework-agnostic **`<kc-*>` web components** (`.ai/chat/elements`) — the
drop-in shells (`<kc-chat>`, …) when you just want batteries included.
Both work in the same app; reach for whichever fits the surface you're building.
## Install & setup
```bash
npm i .ai/chat
```
`solid-js` is a peer dependency — install it if you haven't already:
```bash
npm i solid-js
```
Import the design tokens **once**, near your app entry:
```ts
import '@kitn.ai/chat/theme.css';
```
The `.ai/chat` entry ships as **source** (TSX), so your bundler compiles and tree-shakes it
alongside your own Solid code — you only pay for what you import.
## Quick start — native components
Compose the native components directly in your JSX. Drive the prompt input with a `createSignal`,
and let the components fill their container — size them with flex / `class="h-full"` rather than a
hard-coded `height: 100vh`.
```tsx
import {
ChatConfig, ChatContainer, ChatContainerContent,
Message, MessageContent,
PromptInput, PromptInputTextarea, PromptInputActions,
} from '.ai/chat';
import '@kitn.ai/chat/theme.css';
import { createSignal } from 'solid-js';
function Chat() {
const [input, setInput] = createSignal('');
// The components fill their box — give them a flex parent and let
// ChatContainer grow with `h-full`/flex rather than a fixed viewport height.
return (
<div class="flex flex-col h-full">
<ChatConfig proseSize="sm">
<ChatContainer class="h-full">
<ChatContainerContent class="space-y-4 p-4">
<Message>
<MessageContent markdown>{`Ask me anything.`}</MessageContent>
</Message>
</ChatContainerContent>
</ChatContainer>
<PromptInput value={input()} onValueChange={setInput} onSubmit={() => setInput('')}>
<PromptInputTextarea placeholder="Ask anything..." />
<PromptInputActions>{/* your buttons */}</PromptInputActions>
</PromptInput>
</ChatConfig>
</div>
);
}
```
`<ChatContainer>` is **transport-agnostic**: it owns the conversation UI, you own the request.
Render your message list inside `<ChatContainerContent>` (a `<For>` over your signal of messages),
and append the user turn — then stream the assistant reply — in `onSubmit`.
## Go further — compose & the web components
### The native components *are* the granular composition
There's no separate "advanced" component set — the pieces above (`ChatContainer`, `Message`,
`PromptInput`) plus the feature components (`Markdown`, `CodeBlock`, `Reasoning`, `Tool`,
`Conversations`, `ModelSwitcher`, …) **are** the building blocks. Assemble them into any layout you
like: a sidebar next to a thread, a split view, a custom composer — it's all just Solid JSX.
For a resizable layout, use the native `Resizable` convenience component with one `ResizablePanel`
per pane (handles are auto-inserted between visible panels). Each panel takes `defaultSize`
(px or `%`) plus optional `minSize`/`maxSize`; listen for `onChange` (an array of percent sizes) to
persist the layout.
```tsx
import { Resizable, ResizablePanel } from '@kitn.ai/chat';
function Workspace() {
return (
<div class="flex flex-col h-full">
<Resizable orientation="horizontal" withHandle onChange={(sizes) => persist(sizes)}>
<ResizablePanel defaultSize="25%" minSize="200px">
{/* your conversation sidebar */}
</ResizablePanel>
<ResizablePanel>
{/* the message thread + prompt input */}
</ResizablePanel>
</Resizable>
</div>
);
}
```
> **Full reference:** the **[Solid (Advanced)](?path=/docs/solid-advanced-overview--docs)** sidebar
> tier documents every native building block — the composed **Elements** (message, tool, reasoning,
> …) and the low-level **Primitives** (button, tooltip, dropdown, …) they're built on.
### Prefer the drop-in shell? Use the web component
When you just want a whole chat in one tag, register the `<kc-*>` elements and use `<kc-chat>`.
Solid sets rich data as DOM **properties** on custom elements (so arrays/objects pass through
without stringifying), and you listen for CustomEvents with Solid's `on:` namespace:
```tsx
import '@kitn.ai/chat/elements'; // registers the <kc-*> elements once
import { createSignal } from 'solid-js';
function Shell() {
const [messages, setMessages] = createSignal([
{ id: '1', role: 'assistant', content: 'Hello! How can I help?' },
]);
const onSubmit = (e: CustomEvent<{ value: string }>) => {
setMessages((prev) => [
...prev,
{ id: crypto.randomUUID(), role: 'user', content: e.detail.value },
]);
// ...call your model, then append an assistant message
};
return (
<div class="flex flex-col h-full">
<kc-chat
// `prop:` forces a property assignment (not an attribute) for rich data.
prop:messages={messages()}
on:kc-submit={onSubmit}
style={{ flex: 1, 'min-height': 0 }}
/>
</div>
);
}
```
For a resizable web-component layout, use `<kc-resizable>` the same way (set properties, listen
with `on:`) — though in a Solid app the native `Resizable` above gives you tighter control.
> **See it all assembled:** **[Examples → Full Chat App](?path=/story/examples-full-chat-app--default)**
> wires a sidebar, threaded markdown, reasoning, a tool call, a model switcher, a context meter, and
> a rich prompt input into one screen — a working reference to crib from.
## When to use which
- **Native components** (`.ai/chat`) — full compositional control and the **smallest output**
for a Solid app, since they compile and tree-shake with your own code. The recommended path when
you're building in Solid.
- **Web components** (`.ai/chat/elements`) — the **fastest drop-in** and fully
framework-agnostic. Reach for `<kc-chat>` (or any `<kc-*>` shell) when you want batteries included
or you're sharing UI across frameworks.
Mix freely: a native composed thread on one screen, a drop-in `<kc-chat>` on another.