Skip to content

Repository files navigation

AI/UI

The web UI layer for AI apps. Works anywhere you can put HTML.

Threads, workspaces, artifacts, tool and reasoning panels, generative UI, voice.

In your framework: React, Next.js, Vue, Svelte, Angular, SolidJS, TanStack Start, or plain HTML.

Or on a platform you don't control: Shopify, WordPress, Webflow, Salesforce, HubSpot, or anywhere a <script> tag is the only way in.

One implementation, not one port per framework, because they're web components. The usual objections to that are answered below.

Docs · Storybook · npm · Security policy

Quickstart

npm create kai@latest

It asks for a framework, then for a backend where there is more than one to choose from, and writes a project that runs. Every axis with a single possible answer today — the layout, the feature set, and the backend on the frameworks that can host nothing but the local mock — it states rather than asking, so nothing gets decided for you in silence. Press Enter through every prompt and you get React, full screen, and the kit's own mock: a real streaming turn on the first npm run dev, with no API key and nothing to host.

npx create-kai@latest --list prints the frameworks, layouts, features and gateways it can scaffold today, and marks the ones it cannot. Read that rather than a list written here; the roster moves.

Add it to an app you already have

npm install @kitn.ai/ui

Drop in, or compose

One tag gets you a working chat:

<kai-chat></kai-chat>

You are not stuck with its layout. <kai-chat> is one preset over pieces you can use directly, <kai-workspace> is another, and the pieces go well past chat. Arrange your own:

<kai-resizable>
  <kai-resizable-item size="280px">
    <kai-conversations></kai-conversations>
  </kai-resizable-item>
  <kai-resizable-item>
    <kai-thread></kai-thread>
    <kai-prompt-input></kai-prompt-input>
  </kai-resizable-item>
</kai-resizable>

That is what every starter in examples/starters is, once per framework. Feed messages in, listen for kai-submit, and it's a chat app. The wiring: Compose a message thread.

Wrapper or tag

Rendering goes three ways, and they are not symmetric.

Framework How you render
React, Next.js, TanStack Start Typed wrappers from @kitn.ai/ui/react (<Thread>, <PromptInput>, <Conversations>), or the raw tags. The wrappers are the default and are generated from the same build as the web components, so events arrive as React props (onSubmit for kai-submit) and each one registers its own element on mount.
Vue, Svelte, Angular, plain HTML The tags, after import '@kitn.ai/ui/web-components'. These set DOM properties and listen for DOM events natively, so there's no wrapper layer to add. Vue needs isCustomElement in its vite config and Angular needs CUSTOM_ELEMENTS_SCHEMA; Svelte and HTML need nothing.
SolidJS Genuinely different. @kitn.ai/ui/solid hands you the SolidJS components themselves, with no web components in the picture. Solid is the layer everything else is built from.

Wiring a web component by hand, in any framework:

<script type="module">
  import '@kitn.ai/ui/web-components';

  // Registration is async (that's what keeps the import SSR-safe), so wait for
  // the element before setting properties or the upgrade clobbers them.
  await customElements.whenDefined('kai-thread');

  // A message's content is an ordered `parts` array.
  document.querySelector('kai-thread').messages = [
    { id: '1', role: 'assistant', parts: [{ type: 'text', text: 'Ask me anything.' }] },
  ];
</script>

The same thing per framework: Getting started.

The rest of the entry points

Import What it gives you
@kitn.ai/ui/state Pure folds over ChatMessage[]: createAssistantStream, appendTextPart, upsertToolPart. No I/O.
@kitn.ai/ui/wire Provider SSE in, message parts out: readOpenAIStream, readAnthropicStream, toOpenAIMessages.
@kitn.ai/ui/theme.css Tailwind v4 token source for your own markup (theme.tokens.css is the plain-CSS build). Retheming the web components needs no import: set --kai-color-* on :root.

Also shipped: @kitn.ai/ui/web-components/<name> for one web component at a time, @kitn.ai/ui/autoloader to load each on demand on a static or CDN-served page with no bundler, @kitn.ai/ui/schemas for the generative-UI card schemas, and @kitn.ai/ui/provider for cards served from another origin. The authoritative list is the exports map in packages/ui/package.json.

The kit parses, your app fetches. There's no HTTP client, no key handling and no provider SDK in here: wire reads a stream you opened, which is why your keys never have to come near it.

The web-component objections

They're fair, and mostly historic. Where they still bite, this kit answers them:

  • React interop. @kitn.ai/ui/react is generated from the same build that generates the web components, so props are typed and events are React props. No ref plumbing to set an array.
  • SSR. Registration is client-only by construction, and the React wrappers register in an effect. CI renders every server entry in a DOM-free Node process on each run (verify:ssr), and the Next.js and TanStack Start starters are server-rendered.
  • Types. The React wrappers are generated, not hand-maintained, and a custom-elements manifest ships for editor tag completion.
  • Styling. Shadow DOM keeps your CSS out, which is also why you can't override a selector. Theming runs on --kai-color-* custom properties, which cross the boundary by design, and the web components expose CSS parts for the pieces worth reaching.
  • No build step. The web components load from a CDN in a plain <script> tag, so they work on a host with no bundler to hook into. @kitn.ai/ui/autoloader fetches each one on demand as its tag appears.

Three things every consumer hits

  • Arrays and objects are set in JavaScript, not as HTML attributes. messages, suggestions, models and the rest are assigned as properties. Only scalars (placeholder, loading, theme) work as attributes.
  • Events are non-bubbling kai-* CustomEvents. Listen on the element itself, never a parent. Submit is kai-submit and the text is event.detail.value.
  • Updating needs a new array and a new object for each item you changed. The new array reference is what tells the element something changed; the new item object is what makes the change visible. Adds, removes and reorders need only the fresh array — editing an existing item needs both, and mutating it in place renders nothing even inside a fresh array.

Every property, event and method for every web component: docs/web-components.md.

The kai MCP

The kit ships a stdio MCP server as its own package, @kitn.ai/mcp, so an AI coding harness can build with this library instead of guessing at it:

claude mcp add kai -- npx -y @kitn.ai/mcp

Four tools: component_reference (the real API for any kai-* web component, generated from the build), scaffold (a working chat surface wired to your framework and backend), theme (brand it from a color or a description), debug (the classic mistakes). It runs locally and makes no network calls. Config for other harnesses: For AI agents.

Status

Pre-1.0. Releases are cut by release-please from conventional commits with bump-minor-pre-major set, so a breaking change lands in a minor, not a major. Pin an exact version if that matters to you, and read the changelog before raising one.

Found a vulnerability? SECURITY.md has the private channel and what's in scope. Don't use the issue tracker for it.

Working in this repo

pnpm + NX workspace, Node 22+.

  • packages/ui: the published kit (@kitn.ai/ui), its Storybook, and the kai MCP.
  • packages/create-kai: the npm create kai scaffolder.
  • apps/docs: the Astro Starlight site behind ui.kitn.ai, consuming the kit via workspace:*.
  • examples: a hand-composed starter per framework, plus static demos. create-kai copies its templates from examples/starters.
pnpm install
pnpm dev          # Storybook (6006) and the docs site (4321) together
pnpm build        # every workspace, ui before docs
pnpm test         # every workspace's tests
pnpm typecheck

pnpm example:react and its siblings need packages/ui/dist/, which is gitignored, so run pnpm build:ui first.

CLAUDE.md is where the expensive knowledge lives: what a fresh clone needs before the test suite means anything, which caches lie, and which orderings are load-bearing. Read it before your first change.

License

MIT. See LICENSE.

About

A component library of framework agnostic web components for AI chat built using Solid.js

Resources

Security policy

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages