Svelte
kai-* web components work in Svelte without wrappers or special directives. The Svelte compiler sets DOM properties directly when you pass non-primitive values, and on:eventname wires up CustomEvents — no boilerplate required.
Install
Section titled “Install”npm install @kitn.ai/uiRegister every kai-* element once, near your app entry point:
// src/main.js or inside a <script> block in your root componentimport '@kitn.ai/ui/elements';One import covers your entire app. No CSS import is needed — each element is styled inside its own Shadow DOM. Add @kitn.ai/ui/theme.css only if you want to override design tokens (see Theming).
Pass data and handle events
Section titled “Pass data and handle events”The rule for every kai-* element: rich data in as properties, interactions out as events.
Svelte maps cleanly to this pattern:
| What | Svelte syntax | Notes |
|---|---|---|
| String attribute | prop="value" | Standard HTML attribute |
| Array or object | {prop} shorthand | Svelte assigns as a DOM property — never stringified |
| Listen for an event | on:kai-eventname={handler} | handler(e) — data is on e.detail |
Example — streaming chat
Section titled “Example — streaming chat”<kai-chat> is transport-agnostic: you own the API call, the element owns the UI. Pass a messages array and handle kai-submit to stream replies back into state.
<script> import '@kitn.ai/ui/elements';
let messages = [ { id: '1', role: 'assistant', content: 'Hello! How can I help?' }, ];
async function handleSubmit(e) { const userText = e.detail.value; const history = [ ...messages, { id: crypto.randomUUID(), role: 'user', content: userText }, ]; messages = history;
const assistantId = crypto.randomUUID(); messages = [...history, { id: assistantId, role: 'assistant', content: '' }];
let reply = ''; for await (const token of streamFromYourAPI(history)) { reply += token; // Reassign the array so Svelte detects the update. messages = messages.map((m) => m.id === assistantId ? { ...m, content: reply } : m ); } }</script>
<div style="display: flex; flex-direction: column; height: 100dvh;"> <kai-chat {messages} suggestions={['Summarize the chat', 'Start fresh']} on:kai-submit={handleSubmit} style="flex: 1; min-height: 0;" /></div>kai-chat is display: block and fills its container. Wrap it in a flex column and give it flex: 1 rather than a hard-coded height so it adapts to the viewport.
Add a conversation sidebar
Section titled “Add a conversation sidebar”Compose <kai-conversations> alongside <kai-chat> for a multi-thread layout. Each element takes its data as properties and emits its own events.
<script> import '@kitn.ai/ui/elements';
let conversations = loadConversations(); let activeId = conversations[0]?.id; let messages = loadMessages(activeId);
function selectConversation(e) { activeId = e.detail.id; messages = loadMessages(activeId); }</script>
<div style="display: flex; height: 100dvh;"> <kai-conversations {conversations} {activeId} on:kai-conversation-select={selectConversation} on:kai-new-chat={() => startNewConversation()} style="width: 300px; flex-shrink: 0;" />
<kai-chat {messages} on:kai-submit={(e) => sendMessage(e.detail.value)} style="flex: 1; min-width: 0;" /></div>Key events reference
Section titled “Key events reference”| Element | Event | e.detail |
|---|---|---|
kai-chat | kai-submit | { value: string } |
kai-chat | kai-value-change | { value: string } |
kai-chat | kai-model-change | { model: string } |
kai-conversations | kai-conversation-select | { id: string } |
kai-conversations | kai-new-chat | {} |
kai-conversations | kai-toggle-sidebar | {} |
kai-attachments | kai-remove | { id: string } |
kai-resizable | kai-change | { sizes: number[] } |
Every element’s full prop and event list is on its component page in the Components reference.