Open-ended HTML

Generate self-contained HTML experiences and render them in an AgentInterface detailed view.

OpenUI usually asks the model to compose components from a library. For open-ended generation, the model can instead produce a complete HTML/CSS/JavaScript experience as the props of one OpenUI component.

View the complete example on GitHub →

How it works

The example defines a small library: a Response root, a Markdown component for normal replies, and an HtmlArtifact component the model uses only when asked to build something interactive.

const HtmlArtifactSchema = z.object({
  title: z.string(),
  document: z.string(),
});

export const HtmlArtifact = defineComponent({
  name: "HtmlArtifact",
  description: "Renders a self-contained HTML/CSS/JavaScript experience.",
  props: HtmlArtifactSchema,
  component: HtmlArtifactRenderer,
});

export const library = createLibrary({
  root: "Response",
  components: [Response, Markdown, HtmlArtifact],
});

The model decides per reply: most responses are a Response with a single Markdown child; a request like "build me a sorting visualizer" produces an HtmlArtifact.

HtmlArtifactRenderer uses the existing chat stream:

  1. useIsStreaming() tracks whether the document is still arriving.
  2. A compact preview remains inline in the conversation.
  3. DetailedViewPanel opens the result on the right.
  4. The Raw tab shows the incoming source.
  5. The Rendered tab shows a loading state, then switches to a sandboxed iframe when the stream completes.

No additional streaming endpoint or tool call is required.

Teach the model

Generate the system prompt with openui generate. Prompt rules should tell the model to:

  • use Markdown for normal conversation and HtmlArtifact only when asked to build something interactive;
  • produce a self-contained HTML document or fragment;
  • use inline CSS and JavaScript;
  • avoid external scripts, styles, fonts, images, and network requests;
  • omit Markdown fences;
  • correctly escape the HTML inside the OpenUI Lang string.

See the example's library.tsx for the complete prompt options.

Before production

Generated HTML is untrusted content. Normalize and validate the document, enforce a Content Security Policy, restrict network access, keep the iframe sandbox narrow, and validate any messages crossing the iframe boundary.

On this page