kai-artifact
Show an AI-generated deliverable beside the conversation — a web page, doc, image, or PDF — in a sandboxed iframe with a nav toolbar and a switchable Code view.
- Shadow DOM
- Sandboxed iframe
- Preview + Code tabs
- Configurable toolbar
- 4 events
Preview
Section titled “Preview”Point src at your hosted artifact and set files in JavaScript (it’s an array, so it can’t be an HTML attribute) for the Code tab.
<kai-artifact src="https://your.app/artifacts/abc/index.html" style="display:block;height:520px"></kai-artifact><script type="module"> import '@kitn.ai/ui/elements';
await customElements.whenDefined('kai-artifact');
const el = document.querySelector('kai-artifact'); el.files = [ { path: 'index.html', url: '…/index.html', type: 'html', code: '<!DOCTYPE …>' }, { path: 'styles.css', url: '…/styles.css', type: 'other', language: 'css', code: '…' }, ]; el.addEventListener('kai-navigate', (e) => console.log(e.detail.url));</script>files— each entry needs apath; addurlfor the preview,code+languagefor the Code tab, andtype(html | pdf | image | other). Folders come from the/in paths.- Toolbar — hide any default control with its
no-*flag (no-nav,no-reload,no-home,no-path-field,no-tabs);expandableandopen-in-tabare opt-in. - Sandbox defaults to
allow-scripts allow-forms. Widen it only for trusted content.
Examples
Section titled “Examples”Code view
Section titled “Code view”Preview only
Section titled “Preview only”Hide the whole toolbar for a chrome-free embedded tile.
Open in new tab
Section titled “Open in new tab”Standalone
Section titled “Standalone”Rounded, bordered chrome for an artifact rendered outside a panel — a modal or inline tile.
Expandable
Section titled “Expandable”An expand-to-fill button that fires kai-maximize-change, plus the open-in-tab control.
| Property | Type | Default | Notes |
|---|---|---|---|
| theme | "light" | "dark" | "auto" | 'auto' | Color mode (`auto` follows prefers-color-scheme). |
| src | string | — | URL the preview iframe frames. Consumer-controlled. |
| files | [] | Files for the Code tab tree + each file's preview `url`. Omit for a preview-only artifact (the Code tab then has nothing to show; pair it with `no-tabs` to hide the toggle). Set as a JS property (array). | |
| tab | "preview" | "code" | — | Controlled active tab: `preview` or `code`. When set, the artifact follows it (re-asserted on change). Leave unset for an uncontrolled tab (see `defaultTab`). |
| defaultTab | "preview" | "code" | — | Uncontrolled INITIAL tab (used only when `tab` is unset). Default `preview`. Seeds the starting tab; the user can then switch freely without the consumer re-asserting a controlled `tab`. |
| activeFile | string | — | Selected file path. Syncs the tree highlight, Code source, and preview. |
| sandbox | string | 'allow-scripts allow-forms' | iframe `sandbox` override. Secure default `allow-scripts allow-forms` (NOT `allow-same-origin`). |
| iframeTitle | string | — | Accessible title for the preview iframe. |
| maximized | boolean | false | Reflects the artifact's own maximized view-state (usually driven by the protocol). |
| expandable | boolean | false | Show the expand-to-fill button (OPT-IN). |
| openInTab | boolean | false | Show the open-in-new-tab button (OPT-IN). |
| noNav | boolean | false | Hide back/forward. |
| noReload | boolean | false | Hide reload. |
| noHome | boolean | false | Hide home. |
| noPathField | boolean | false | Hide the address field. |
| noTabs | boolean | false | Hide the Preview|Code toggle. |
| standalone | boolean | false | Standalone chrome: rounded corners + border (else square, borderless in-panel). |
| readonlyPath | boolean | false | Show the address but make it read-only (visible, nav-tracking, non-editable). |
| displayUrl | string | — | Friendly address shown in the path field instead of the real current url (read-only, non-navigable). Use when the framed url is not consumer-facing (e.g. a `data:` blob) so a clean address shows instead of leaking it. Scalar string: set as the `display-url` attribute or the `displayUrl` property. |
Events
Section titled “Events”| Event | Detail | Notes |
|---|---|---|
| kai-file-select | | Fired when a file is selected. `detail.path`. |
| kai-maximize-change | | Artifact's own maximize button toggled (consumer-observable; non-bubbling). |
| kai-maximize-intent | | The maximize PROTOCOL intent, raised as a raw bubbling + composed CustomEvent (not through `dispatch`) so an enclosing `<kai-resizable>` can catch it and maximize the containing panel. Declared here so it is typed and reaches the generated API. Listen for it to drive maximize from your own chrome, or re-emit it to trigger one. |
| kai-navigate | | Fired when the preview navigates. `detail.url` = the new location. |
| kai-tab-change | | Fired when the Preview|Code tab changes. `detail.tab`. |
Methods
Section titled “Methods”| Method | Signature | Notes |
|---|---|---|
| back | (): void | Go back in the artifact's own history stack (no-op when there's no prior entry). |
| forward | (): void | Go forward in the history stack (no-op when there's no forward entry). |
| reload | (): void | Force-reload the current preview url (also re-renders an inline PDF). |
| home | (): void | Navigate to the `src` home url (no-op when there's no `src`). |
| navigate | (url: string): void | Push + load a url in the preview, the path-field submit path (fires kai-navigate). |
| selectFile | (path: string): void | Select a file by path: highlights the tree, shows its source, navigates the preview (fires kai-file-select + kai-navigate). Named selectFile to avoid the `activeFile` prop. |
| openExternal | (): void | Open the current url in a new browser tab (no-op when there's no concrete url). Named openExternal, NOT openInTab, which is a prop (toolbar button visibility). |
| maximize | (): void | Enter the maximized view-state (fires kai-maximize-change{maximized:true}). Named maximize, NOT maximized, which is a prop. |
| restore | (): void | Exit the maximized view-state (fires kai-maximize-change{maximized:false}). |
Composed from
Section titled “Composed from”This element wraps these SolidJS components — reach for them directly when you need finer control than the props expose.
Artifact