---
title: GenUI
description: Use Generative UI with Chat components.
---

GenUI lets assistant messages render structured UI instead of plain text. To make it work, you need both sides of the setup:

- `componentLibrary` on the frontend so OpenUI knows how to render components
- a generated system prompt on the backend so the model knows what it is allowed to emit

Passing `componentLibrary` alone is not enough.

The frontend and backend have different jobs here:

- the frontend renders structured responses through `componentLibrary`
- the backend loads the generated system prompt and sends it to the model with each request

If either side is missing, the model falls back to plain text or emits components the UI cannot render.

Generate the system prompt with the CLI:

```bash
npx @openuidev/cli@latest generate ./src/library.ts --out src/generated/system-prompt.txt
```

The CLI auto-detects exported `PromptOptions` alongside your library, so examples and rules are included automatically. See [System Prompts](/docs/openui-lang/system-prompts) for details.

## Use the chat library

`openuiChatLibrary` is optimised for conversational chat: every response is wrapped in a `Card`, and it includes chat-specific components like `FollowUpBlock`, `ListBlock`, and `SectionBlock`.

```tsx
import { openAIAdapter, openAIMessageFormat } from "@openuidev/react-headless";
import { FullScreen } from "@openuidev/react-ui";
import { openuiChatLibrary } from "@openuidev/react-ui/genui-lib";

export default function Page() {
  return (
    <FullScreen
      processMessage={async ({ messages, abortController }) => {
        return fetch("/api/chat", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            messages: openAIMessageFormat.toApi(messages),
          }),
          signal: abortController.signal,
        });
      }}
      streamProtocol={openAIAdapter()}
      componentLibrary={openuiChatLibrary}
      agentName="Assistant"
    />
  );
}
```

In this setup:

- The system prompt is generated at build time via the CLI and loaded by the backend
- `openAIMessageFormat.toApi(messages)` converts messages before sending
- `componentLibrary={openuiChatLibrary}` tells the UI how to render the model output
- `openAIAdapter()` parses raw SSE chunks from the backend

This is the minimal complete pattern for GenUI in a chat interface. For a non-chat renderer or custom layout, use `openuiLibrary` and `openuiPromptOptions` from the same import path.

<div className="grid md:grid-cols-2 gap-6 my-6">
  <div>
    <p className="text-sm text-center font-medium mb-2">Plain text response</p>
    ![Plain text response](/docs/images/chat/genui-text-response.png)
  </div>
  <div>
    <p className="text-sm text-center font-medium mb-2">GenUI response</p>
    ![GenUI rendered response](/docs/images/chat/genui-response.png)
  </div>
</div>

## Use your own library

If you need domain-specific components, keep the same request flow and swap in your own library definition:

First, generate the system prompt from your custom library:

```bash
npx @openuidev/cli@latest generate ./src/lib/my-library.ts --out src/generated/system-prompt.txt
```

Then wire up the frontend — it only needs the component library for rendering:

```tsx
import { openAIMessageFormat, openAIReadableStreamAdapter } from "@openuidev/react-headless";
import { FullScreen } from "@openuidev/react-ui";
import { myLibrary } from "@/lib/my-library";

<FullScreen
  processMessage={async ({ messages, abortController }) => {
    return fetch("/api/chat", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        messages: openAIMessageFormat.toApi(messages),
      }),
      signal: abortController.signal,
    });
  }}
  streamProtocol={openAIReadableStreamAdapter()}
  componentLibrary={myLibrary}
  agentName="Assistant"
/>;
```

Your custom library needs two things:

- a `createLibrary()` result, so the CLI can generate the system prompt and the frontend can render components
- optional `PromptOptions` export for examples and rules (auto-detected by the CLI)

Your backend loads the generated prompt file and sends it to the model alongside the message history.

## Related guides

- [End-to-End Guide](/docs/chat/from-scratch)
- [Connecting to LLM](/docs/chat/connecting)
- [Define Components](/docs/openui-lang/defining-components)
