Workspace app
One element gives you the full workspace: a resizable, collapsible sidebar listing past conversations grouped by recency, plus a streaming chat thread. Select a conversation, start a new one, or send a message below.
How it works
Section titled “How it works”<kai-workspace> wraps <kai-conversations> and <kai-chat> inside a resizable split. You pass a flat conversations array (the component auto-buckets by recency) and the active thread’s messages. Three events drive all the interactivity:
<kai-workspace id="ws"></kai-workspace>
<script type="module"> import '@kitn.ai/ui/elements';
const ws = document.getElementById('ws');
// Seed conversations (assign in JavaScript — arrays can't be attributes). ws.conversations = [ { id: 'c1', title: 'Migrating the dashboard to web components', scope: { type: 'collection' }, messageCount: 4, lastMessageAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }, // … more conversations ];
// Seed the active thread. ws.messages = [ { id: 'u1', role: 'user', content: 'How do I share state across the panels?' }, { id: 'a1', role: 'assistant', content: 'Keep one source of truth and reassign it on each change …', actions: ['copy', 'like', 'dislike'] }, ]; ws.activeId = 'c1';
// Swap the thread when the user picks a conversation. ws.addEventListener('kai-conversation-select', (e) => { ws.activeId = e.detail.id; ws.messages = threadFor(e.detail.id); // load from your store });
// Clear the thread and start fresh. ws.addEventListener('kai-new-chat', () => { ws.messages = []; ws.activeId = undefined; });
// Stream a reply — identical pattern to <kai-chat>. ws.addEventListener('kai-submit', async (e) => { const { value } = e.detail; const aId = crypto.randomUUID(); ws.messages = [ ...ws.messages, { id: crypto.randomUUID(), role: 'user', content: value }, { id: aId, role: 'assistant', content: '' }, ]; ws.loading = true; for await (const token of streamFromYourModel(value)) { ws.messages = ws.messages.map((m) => m.id === aId ? { ...m, content: m.content + token } : m, ); } ws.loading = false; });</script>Key data shapes:
conversations— each entry needsid,title,scope({ type: 'collection' }),messageCount,lastMessageAt, andupdatedAt. The component uses the timestamps to bucket rows into “Today”, “Yesterday”, “Last 7 days”, etc.messages— the sameChatMessage[]shape as<kai-chat>:id,role,content, plus optionalactions,reasoning,tools, andattachments.
Sidebar controls:
| Prop | Default | Effect |
|---|---|---|
sidebarWidth | 22 | Initial sidebar width (%) |
sidebarMinWidth | 200 | Minimum sidebar width (px) |
sidebarMaxWidth | 420 | Maximum sidebar width (px) |
sidebarCollapsed | false | Start with sidebar collapsed |
The user can drag the divider to resize or click the sidebar toggle. Listen to kai-sidebar-toggle (detail.collapsed) to persist the state.
Next steps
Section titled “Next steps”- Drop-in chat — the simpler single-thread starting point and streaming loop.
kai-workspacereference — every prop and event, including model switcher, context meter, and slash commands.kai-conversationsreference — use this element standalone when you want to build your own layout instead of using the pre-composed workspace.- Theming — brand the sidebar (
--color-sidebar) and chat thread in one pass.