# Loading the elements

Three ways to load the kai-* elements — register all, import per-element, or autoload on demand. Pick the one that fits your setup.

There are three ways to get the `kai-*` elements onto a page. They render the same components — the difference is *how* their code reaches the browser. Most apps want the first one.

## Quick comparison

| Strategy | Import | Reach for it when |
|---|---|---|
| **Register all** | `@kitn.ai/ui/elements` | The default. You use several elements, or you just want it to work. Works in SSR. |
| **Per-element** | `@kitn.ai/ui/elements/chat` | You use only a couple of elements and your build tree-shakes. |
| **Autoloader** | `<script>` (CDN / static) | No build step — a CDN or static page. Loads each element on demand. |

> **tip:** 
`import '@kitn.ai/ui/elements'` registers every element in one import and works everywhere, including SSR. Reach for the other two only when you have a specific reason — a build that tree-shakes, or a no-build CDN page.

## Register all (default)

```js

```

One import, every `kai-*` element registered. The simplest setup, and the SSR-safe entry point — the import is side-effect-only and doesn't touch `document` until the browser runs it, so it won't throw in a server render.

## Per-element imports

Import an element by its file basename, and your bundler includes only that element's code:

```js

```

> **tip:** 
That single import is everything a chat needs. `<kai-chat>` already bundles everything it renders — messages, markdown, **code highlighting, reasoning, tool calls, attachments, the prompt input**, model switcher, scroll button. You do **not** import those separately, and there is no internal sub-part to forget.

You only add another import for an **additional standalone element you place in your own markup** — e.g. a `<kai-artifact>` beside the chat. That's one import per element *you* write into the HTML.

And it fails loud, not silent: if you place an element but forget its import, that element renders empty (un-upgraded) instead of breaking the rest of the page — and the `kai` MCP's `debug` / `component_reference` tools name the exact import to add. (Generative-UI **cards** — `kai-confirm`, `kai-form`, … — are also standalone elements, so add them only if your assistant renders card payloads.)

The import path is the element's filename in `dist/elements/` — usually the tag minus the `kai-` prefix. You only need a row below for an element you place in your markup yourself; the message / markdown / reasoning / input parts of a chat are already inside `kai-chat`:

| Element | Import |
|---|---|
| `<kai-chat>` | `@kitn.ai/ui/elements/chat` |
| `<kai-code-block>` | `@kitn.ai/ui/elements/code-block` |
| `<kai-message>` | `@kitn.ai/ui/elements/message` |
| `<kai-prompt-input>` | `@kitn.ai/ui/elements/prompt-input` |
| `<kai-markdown>` | `@kitn.ai/ui/elements/markdown` |
| `<kai-reasoning>` | `@kitn.ai/ui/elements/reasoning` |
| `<kai-attachments>` | `@kitn.ai/ui/elements/attachments` |
| `<kai-artifact>` | `@kitn.ai/ui/elements/artifact` |

> **caution:** 
Per-element imports are client-only. In SSR frameworks (Next.js, Nuxt, SvelteKit, etc.) wrap them in a client-side boundary — a `'use client'` component in Next.js, an `onMount` in Svelte, or a `<ClientOnly>` wrapper in Nuxt.

## Autoloader

The autoloader watches the DOM and registers each element on demand — only the tags present on a given page are ever loaded.

It is a **CDN / static-file** tool: load it from a `<script type="module">` tag. It is **not** importable through a bundler — Vite and webpack relocate it away from the element files and its on-demand imports 404. In a bundled app, use [per-element imports](#per-element-imports) instead.

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/@kitn.ai/ui/dist/elements/autoloader.js"></script>
```

Here it is running live. This iframe loads **only** the autoloader — watch the panel for the modules it fetches on demand, then add an element and see it load on the fly:

<iframe
  src="/autoloader-demo.html"
  title="Live kai-* autoloader demo"
  loading="lazy"
  style="width:100%; height:460px; border:1px solid var(--sl-color-gray-5); border-radius:12px; margin:1.25rem 0;"
></iframe>

On import it scans for undefined `kai-*` elements and starts a `MutationObserver`. Any `kai-*` element added to the DOM later — including ones injected by client-side routing — is registered the moment it appears.

```html
<!-- Only kai-chat loads. The others register only if you add them. -->
<kai-chat style="display:block; height:100dvh;"></kai-chat>

<script type="module">

  const chat = document.querySelector('kai-chat');
  chat.messages = [{ id: '1', role: 'assistant', content: 'Hello!' }];
  chat.addEventListener('kai-submit', (e) => console.log(e.detail.value));
</script>
```

> **caution:** 
The autoloader resolves element modules relative to its own URL and uses `document` + `MutationObserver`. Load it from a `<script type="module">` on a CDN or static host. Do **not** `import '@kitn.ai/ui/autoloader'` in a bundled (Vite/webpack/Next) app or a server render — the bundler relocates it and the on-demand imports 404. In a bundled app, use per-element imports or the register-all bundle.

> **tip:** 
An unversioned CDN URL tracks the latest release, which is risky on a pre-1.0 package. Pin an exact version: `https://cdn.jsdelivr.net/npm/@kitn.ai/ui@0.16.0/dist/elements/autoloader.js`.

## Code highlighting

Syntax highlighting (Shiki) loads on demand — per language, the first time a code block with that language renders, with no WebAssembly. If you never render a code block, it never loads. This holds for all three strategies above.

## SSR notes

| Strategy | SSR-safe? |
|---|---|
| `@kitn.ai/ui/elements` | Yes — side-effect only; no `document` on import |
| Per-element (`@kitn.ai/ui/elements/chat`) | No — use inside a client-only boundary |
| Autoloader | No — uses `document`; CDN `<script>`, not for SSR |

For SSR meta-frameworks, see the [meta-frameworks guide](/guides/frameworks/meta-frameworks/) for framework-specific client boundary patterns.
