Configuration
Detailed setup guide for the server prompt, client runtime, adapter configuration, and the main public APIs ToonUI exposes.
This page is the missing bridge between “I installed it” and “I understand how to configure it correctly”.
The core configuration idea
A correct ToonUI setup has four parts:
- server protocol
- model prompt composition
- client runtime
- interaction reinjection
If one of those is vague, the integration becomes fragile.
1. Configure the server protocol
The canonical server entrypoint is createToonProtocol().
import { createToonProtocol } from '@toon-ui/core';
const toon = createToonProtocol();This exposes:
toon.prompttoon.rulestoon.catalogtoon.eventstoon.messages
What each one is for
| API | Purpose |
|---|---|
toon.prompt | canonical instruction set for the model |
toon.rules | structured language rules for custom prompt composition |
toon.catalog | official catalog of components, variants, and examples |
toon.events | factories for reply and submit payloads |
toon.messages | converters from payloads to model/UI message shapes |
2. Configure the model prompt correctly
The most common good setup is:
import { createToonProtocol } from '@toon-ui/core';
const toon = createToonProtocol();
const businessRules = [
'You are helping users manage products and sales.',
'Use ToonUI when structured UI reduces back-and-forth.',
'Do not invent database operations.',
].join('\n');
const toolDescription = [
'Available tools:',
'- searchProducts(query)',
'- createProduct(input)',
'- updateInventory(productId, quantity)',
].join('\n');
export const systemPrompt = [
toon.prompt,
'',
toolDescription,
'',
businessRules,
].join('\n');Why this structure works
- ToonUI defines the UI language
- your app defines business behavior
- tool descriptions define host capabilities
That separation is CLEAN architecture, not convenience theater.
3. Configure the client runtime
You have two main client entrypoints.
Option A — createToonClient()
Use this for the simplest public setup:
import { createToonClient } from '@toon-ui/toon-ui';
const toon = createToonClient();This gives you:
- default adapter
- protocol APIs
- parsing/validation helpers
- rendering compatibility with
ToonMessageandToonRenderer
Option B — createToonReactRuntime()
Use this when your UI layer must be explicit:
import { createToonReactAdapter, createToonReactRuntime } from '@toon-ui/react';
const adapter = createToonReactAdapter({
level: 'default',
});
const toon = createToonReactRuntime({
adapter,
});4. Configure adapter behavior
The adapter is where React ownership becomes explicit.
minimal
const adapter = createToonReactAdapter({
level: 'minimal',
components: {
button: MyButton,
},
});Use it when you want to build your registry manually.
default
const adapter = createToonReactAdapter({
level: 'default',
components: {
button: MyButton,
},
});Use it when you want built-in defaults plus selective overrides.
strict
const adapter = createToonReactAdapter({
level: 'strict',
components: {
text: MyText,
card: MyCard,
form: MyForm,
field: MyField,
button: MyButton,
confirm: MyConfirm,
list: MyList,
item: MyItem,
badge: MyBadge,
alert: MyAlert,
table: MyTable,
},
});Use it when missing component coverage should fail immediately.
5. Configure layout spacing
The React runtime accepts layout options:
const toon = createToonReactRuntime({
adapter,
layout: {
messageGap: 20,
blockGap: 16,
nodeGap: 10,
},
});Use this when you want to tune:
- spacing between assistant message sections
- spacing between blocks
- spacing between nodes inside blocks
6. Configure rendering
High-level rendering with ToonMessage
<ToonMessage
content={assistantContent}
runtime={toon}
onReply={(payload) => append(toon.messages.toUIMessage(payload))}
onSubmit={(payload) => append(toon.messages.toUIMessage(payload))}
/>Use this when the assistant returns:
- prose
- markdown
- fenced
toon-uiblocks
Lower-level rendering with ToonRenderer
Use ToonRenderer when you want finer control over where the structured block appears relative to the rest of the UI.
7. Configure interaction reinjection
This is one of the most important parts of the whole integration.
UI message reinjection
const next = toon.messages.toUIMessage(payload);
append(next);Use this when the interaction should be appended to a UI/chat state list.
Model message reinjection
const next = toon.messages.toModelMessage(payload);
sendToModel(next);Use this when the interaction becomes the next user message for the model loop.
Raw content conversion
const content = toon.messages.toContent(payload);Use this when you only need the normalized interaction string.
8. Configure custom components safely
If you replace components, use the built-in helpers when possible.
Example for buttons:
import {
createToonAdapter,
createToonClient,
getToonButtonProps,
type ToonButtonComponentProps,
} from '@toon-ui/toon-ui';
function MyButton(props: ToonButtonComponentProps) {
return (
<button
className="rounded-md border px-3 py-2"
{...getToonButtonProps(props)}
>
{props.node.label}
</button>
);
}
const adapter = createToonAdapter({
level: 'default',
components: {
button: MyButton,
},
});
const toon = createToonClient({ adapter });Why this matters:
- you keep ToonUI interaction wiring intact
- you customize visuals without breaking semantics
9. Configure parsing and validation in stricter environments
If you want a more defensive setup:
const blocks = toon.extractBlocks(content);
for (const block of blocks) {
const ast = toon.parse(block.raw);
const result = toon.validate(ast);
if (!result.ok) {
throw new Error(
`Invalid ToonUI: ${result.errors.map((error) => error.message).join(', ')}`
);
}
}Use this in:
- tests
- fixtures
- strict server pipelines
- debugging sessions
10. What @toon-ui/toon-ui exposes
The main public client package exposes:
createToonClient()createToonAdapter()ToonMessageToonRendererextractToonMarkdown- all public exports from
@toon-ui/core - all public exports from
@toon-ui/react
That means it is both:
- convenience layer
- public umbrella entrypoint
11. What @toon-ui/react exposes
The React package exposes the explicit runtime layer:
createToonReactAdapter()createToonAdapter()mergeToonComponentRegistry()createToonReactRuntime()assertToonReactAdapter()ToonProviderToonMessageToonRendererextractToonMarkdowngetToonFieldId()getToonButtonProps()getToonInputProps()getToonTextareaProps()getToonCheckboxProps()useToonUI()useToonReply()useToonSubmit()useToonAction()basicPreset()
12. What @toon-ui/core exposes
The core package exposes the protocol and contract layer:
- catalog exports
- types exports
parseToonUI()ToonSyntaxErrorvalidateToonUI()extractToonBlocks()createPrompt()createComponentPrompt()createSyntaxPrompt()createFallbackPrompt()createSafetyPrompt()createExamplesPrompt()createRules()createToonProtocol()createToonCoreRuntime()
13. Recommended production baseline
If you want the default recommendation:
- server:
createToonProtocol() - client:
createToonClient() - rendering:
ToonMessage - reinjection:
toon.messages.toUIMessage()for UI state - stricter loops:
toon.messages.toModelMessage()for model continuation
14. Final configuration checklist
-
toon.promptis included in the system prompt - business rules stay outside ToonUI itself
- the client runtime is created exactly once in the right place
- interaction payloads are reinjected intentionally
- adapter level is chosen deliberately, not by guess
- parsing/validation strategy is defined for your environment