Skip to content

Svelte

Install @gistui/svelte, render a streamed answer in Svelte 5 or SvelteKit, and use your own Svelte components.

Updated View as Markdown

@gistui/svelte is for Svelte 5 and SvelteKit. The package ships its Svelte source, compiled by your app’s build.

npm i @gistui/svelte @gistui/styles @gistui/catalog

Render an answer

<script lang="ts">
  import "@gistui/styles/styles.css";
  import { GistUI } from "@gistui/svelte";

  let { answer, loading } = $props();
</script>

<GistUI source={answer} streaming={loading} onaction={(a) => console.log(a)} />

Pass stream={response.body} instead to let the component read a ReadableStream. Without a component, the use:gistui action renders into any element.

With SvelteKit

src/routes/api/answer/+server.tsts
import { prompt } from "@gistui/catalog";
import { textDeltas, toReadable } from "@gistui/server";
import { OPENAI_API_KEY } from "$env/static/private";

export async function POST({ request }) {
  const { messages } = await request.json();
  const res = await fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: { Authorization: `Bearer ${OPENAI_API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({ model: "gpt-5", stream: true, messages: [{ role: "system", content: prompt().text }, ...messages] }),
  });
  if (!res.ok) return new Response(await res.text(), { status: res.status });
  return new Response(toReadable(textDeltas(res, "openai")));
}

Props and callbacks

Props: source + streaming or stream, inline, theme, color, tokens, darkTokens, classNames, tools, mutations, allowedHosts, paused, initialState, lockUntil, openLinks, autofix (default true), components, library.

Callbacks are lower-case, as Svelte 5 events are: onaction, onerror, onstatechange, onprose, onautofix, ontoolcall.

They mean the same as in every renderer: see Renderer options.

Tools and safety

A program is untrusted: a model wrote it, possibly steered by content it read. It cannot run code.

Option What it does
tools Read-only functions (or an MCP-style client, { callTool }). @query may call them as soon as the UI renders, so nothing here may change anything.
mutations Functions that change something. They run only when a person presses a button.
ontoolcall Called before every tool call with { name, args, kind, nodeId }. Return false to block it.
allowedHosts Hosts that images, video and backgrounds may load from, for example ["cdn.example.com", "*.example.com"]. Set it when the model sees private data.
paused Stops timed data refreshes.

More in Security and Tools and live data.

Your own components

Any Svelte component (shadcn-svelte, Bits UI, your design system) can replace a built-in one.

MyCard.sveltesvelte
<script lang="ts">
  import { GistChildren, type GistUIComponentProps } from "@gistui/svelte";
  let { props }: GistUIComponentProps = $props(); // what the model wrote
</script>

<section class="my-card"><GistChildren /></section>
<GistUI source={answer} components={{ Card: MyCard }} />

Your components see the Svelte context around <GistUI>. For a form field, gistField(() => p.ctx) joins the GistUI Form around it (field.current.name, error, locked, value, setValue).

Navigation

Type to search…

↑↓ navigate↵ selectEsc close