Skip to content
kitn AI/UI

Drop-in widget

The fastest way to a working support widget: describe it in JSON, not code. This guide takes you from nothing to a self-registering script tag.

Run the wizard and answer a few questions:

Terminal window
npm create kai

It asks for a project name first, then what you’re building. Pick “Embedded widget” and it writes <name>.construct.json in a new directory. Every answer maps onto one JSON key, nothing asked twice and nothing invented. Skip the wizard and hand-write the same file if you’d rather; both paths land on the same construct.

Either way, preview it live:

Terminal window
npx @kitn.ai/ui dev widget.construct.json

That works with no install. Once @kitn.ai/ui is installed as a dependency, the bare kai dev widget.construct.json command works too. Either way it starts a server with reload-on-edit: change the JSON, see the widget update.

Here’s a construct using the full widget surface, more than the guided wizard walks you through. The wizard asks for shape, header title, home (on/off, plus a greeting title), starters, attachments, history, and accent color; everything else here (theme.unreadColor, home.recentConversation, home.links) you add by hand. The $schema line gives your editor autocomplete for exactly that.

{
"$schema": "https://ui.kitn.ai/schemas/construct/v1.json",
"name": "acme-support",
"layout": "widget",
"provider": { "mode": "mock" },
"header": { "title": "Acme Support" },
"theme": { "unreadColor": "#38BDF8" },
"home": {
"greeting": { "title": "How can we help?" },
"recentConversation": true,
"links": [
{ "label": "Docs", "href": "https://ui.kitn.ai" },
{ "label": "Contact us" }
]
},
"capabilities": {
"starters": ["Track my order", "Talk to a human"],
"history": { "persistence": "local" },
"conversations": true
}
}
  • $schema points editors at the construct schema for autocomplete and inline validation, so a typo like laylout gets flagged before you run anything.
  • layout: "widget" makes this a floating launcher over an existing page. Use "fullscreen" when the chat is the whole page.
  • provider: { mode: "mock" } is the keyless path: streamed replies come from a built-in mock model, so you get a working preview with no API key and no backend. Switch to a real endpoint by changing this one object, for example { "mode": "endpoint", "url": "/api/chat" }. See the schema for the full provider shape.
  • theme.unreadColor tints the launcher’s unread badge; every other theme token stays at the kit’s default until you set it.
  • home turns on a Home/Messages tab bar. recentConversation: true needs capabilities.conversations to have anything to show; kai validate warns if you set one without the other. A link without an href (like “Contact us” here) is still valid; wire it up to open your own dialog or mailto: link later.
  • capabilities.history persists the thread in localStorage; setting it is why conversations: true is required alongside it, so there’s a list to persist into.

Save it, then check it directly:

Terminal window
npx @kitn.ai/ui validate widget.construct.json

Once the preview looks right, compile to a single self-registering file:

Terminal window
npx @kitn.ai/ui compile widget.construct.json

This emits dist-construct/<name>.js: one file, no externals, that registers a <kai-chat>-backed widget when you load it. Drop it into any page with a <script type="module" src="...">; the generated source sits alongside it in dist-construct/source/ if you want to eject and customize further.

  • Getting Started: wire a <kai-chat> by hand, register the elements, stream a reply.
  • Theming: every token beyond unreadColor.