diff --git a/docs/content/docs/openui-lang/benchmarks.mdx b/docs/content/docs/openui-lang/benchmarks.mdx
index 81d51973e..4dfffd66d 100644
--- a/docs/content/docs/openui-lang/benchmarks.mdx
+++ b/docs/content/docs/openui-lang/benchmarks.mdx
@@ -74,7 +74,7 @@ Generated by GPT-5.2 at temperature 0. Token counts measured with `tiktoken` usi
| e-commerce-product | 2,449 | 2,381 | 1,166 | -52.4% | -51.0% |
| **TOTAL** | **10,180** | **9,948** | **4,800** | **-52.8%** | **-51.7%** |
-OpenUI Lang uses roughly **half the tokens** of both JSON alternatives across all scenarios.
+OpenUI Lang uses up to **67.1% fewer tokens** than both JSON alternatives across all scenarios.
---
@@ -92,7 +92,7 @@ Latency scales linearly with output token count at a given generation speed. At
| settings-panel | 20.73s | 20.08s | 9.00s | **2.3x faster** |
| e-commerce-product | 40.82s | 39.68s | 19.43s | **2.1x faster** |
-The latency advantage compounds with UI complexity. A pricing page or dashboard — the kinds of UIs where Generative UI delivers the most value — render **2–3× faster** with OpenUI Lang.
+The latency advantage compounds with UI complexity. A contact form renders **up to 3.0× faster**, and even complex dashboards and pricing pages — the kinds of UIs where Generative UI delivers the most value — render **2–3× faster** with OpenUI Lang.
---
@@ -134,7 +134,7 @@ The latency advantage compounds with UI complexity. A pricing page or dashboard
### Why is JSON-Render heavier than expected?
-Vercel JSON-Render encodes each element as a separate `{"op":"add","path":"/elements/id","value":{...}}` line. The `op`, `path`, `value`, `type`, `props`, and `children` keys repeat for every node. For deeply nested UIs (dashboards, pricing pages), the structural repetition accumulates significantly — averaging **2.1× the tokens** of OpenUI Lang across our scenarios.
+Vercel JSON-Render encodes each element as a separate `{"op":"add","path":"/elements/id","value":{...}}` line. The `op`, `path`, `value`, `type`, `props`, and `children` keys repeat for every node. For deeply nested UIs (dashboards, pricing pages), the structural repetition accumulates significantly — up to **3.0× the tokens** of OpenUI Lang across our scenarios.
---
diff --git a/docs/content/docs/openui-lang/index.mdx b/docs/content/docs/openui-lang/index.mdx
index 26bee8281..591bafdab 100644
--- a/docs/content/docs/openui-lang/index.mdx
+++ b/docs/content/docs/openui-lang/index.mdx
@@ -58,7 +58,7 @@ cancelBtn = Button("Cancel", "action:cancel_contact", "secondary")
- Start with the default library and render immediately.
+ Start with the OpenUI library and render immediately.
Build custom component contracts with Zod.
diff --git a/docs/content/docs/openui-lang/interactivity.mdx b/docs/content/docs/openui-lang/interactivity.mdx
new file mode 100644
index 000000000..62ba4a59b
--- /dev/null
+++ b/docs/content/docs/openui-lang/interactivity.mdx
@@ -0,0 +1,131 @@
+---
+title: Interactivity
+description: Handle actions, forms, and state in OpenUI components.
+---
+
+OpenUI components can be interactive. The `Renderer` manages form state automatically and exposes callbacks for actions and persistence.
+
+## Actions
+
+When a user clicks a button or follow-up, the component calls `triggerAction`. The `Renderer` wraps this into an `ActionEvent` and fires `onAction`.
+
+```tsx
+ {
+ if (event.type === "continue_conversation") {
+ // event.humanFriendlyMessage — button label or follow-up text
+ // event.formState — field values at time of click
+ // event.formName — scoping form name, if any
+ }
+ }}
+/>
+```
+
+### `ActionEvent`
+
+| Field | Type | Description |
+| :--------------------- | :------------------------------ | :--------------------------------------------- |
+| `type` | `string` | Action type (see built-in types below). |
+| `params` | `Record` | Extra parameters from the component. |
+| `humanFriendlyMessage` | `string` | Display label for the action. |
+| `formState` | `Record \| undefined` | Raw field state at time of action. |
+| `formName` | `string \| undefined` | Form that scoped the action, if any. |
+
+### Built-in action types
+
+```ts
+enum BuiltinActionType {
+ ContinueConversation = "continue_conversation",
+ OpenUrl = "open_url",
+}
+```
+
+- `ContinueConversation` — sends the user's intent back to the LLM.
+- `OpenUrl` — opens a URL in a new tab. Expects `params.url`.
+
+### Using `triggerAction` in components
+
+Inside `defineComponent`, use the `useTriggerAction` hook:
+
+```tsx
+const MyButton = defineComponent({
+ name: "MyButton",
+ description: "A clickable button.",
+ props: z.object({ label: z.string() }),
+ component: ({ props }) => {
+ const triggerAction = useTriggerAction();
+ return ;
+ },
+});
+```
+
+`triggerAction(userMessage, formName?, action?)` — the second and third arguments are optional.
+
+---
+
+## Form state
+
+The `Renderer` tracks field values automatically. Components use `useSetFieldValue` and `useGetFieldValue` to read and write state.
+
+### Persistence
+
+Use `onStateUpdate` to persist field state (e.g. to a message in your thread store) and `initialState` to hydrate it on load.
+
+```tsx
+ {
+ // state is a raw Record of all field values
+ saveToBackend(state);
+ }}
+ initialState={loadedState}
+/>
+```
+
+`onStateUpdate` fires on every field change. The state format is opaque — persist and hydrate it as-is.
+
+### Field hooks
+
+Use these inside `defineComponent` renderers:
+
+| Hook | Signature | Description |
+| :------------------ | :------------------------------------------------------------------------------------------------- | :--------------------------------- |
+| `useGetFieldValue` | `(formName: string \| undefined, name: string) => any` | Read a field's current value. |
+| `useSetFieldValue` | `(formName: string \| undefined, componentType: string \| undefined, name: string, value: any, shouldTriggerSaveCallback?: boolean) => void` | Write a field value. |
+| `useFormName` | `() => string \| undefined` | Get the enclosing form's name. |
+| `useSetDefaultValue`| `(options: { formName?, componentType, name, existingValue, defaultValue, shouldTriggerSaveCallback? }) => void` | Set a default if no value exists. |
+
+---
+
+## Validation
+
+Form fields can declare validation rules. The `Form` component provides a validation context via `useFormValidation`.
+
+```ts
+interface FormValidationContextValue {
+ errors: Record;
+ validateField: (name: string, value: unknown, rules: ParsedRule[]) => boolean;
+ registerField: (name: string, rules: ParsedRule[], getValue: () => unknown) => void;
+ unregisterField: (name: string) => void;
+ validateForm: () => boolean;
+ clearFieldError: (name: string) => void;
+}
+```
+
+Built-in validators include `required`, `minLength`, `maxLength`, `min`, `max`, `pattern`, and `email`. Custom validators can be added via `builtInValidators`.
+
+---
+
+## Next Steps
+
+
+
+ Full Renderer props reference.
+
+
+ Complete lang-react API.
+
+
diff --git a/docs/content/docs/openui-lang/meta.json b/docs/content/docs/openui-lang/meta.json
index 5606f63c0..2b2c934ed 100644
--- a/docs/content/docs/openui-lang/meta.json
+++ b/docs/content/docs/openui-lang/meta.json
@@ -9,6 +9,7 @@
"defining-components",
"system-prompts",
"renderer",
+ "interactivity",
"---Advanced---",
"specification",
"benchmarks"
diff --git a/docs/content/docs/openui-lang/quickstart.mdx b/docs/content/docs/openui-lang/quickstart.mdx
index 2cc45f13f..dfb5c8cc3 100644
--- a/docs/content/docs/openui-lang/quickstart.mdx
+++ b/docs/content/docs/openui-lang/quickstart.mdx
@@ -1,6 +1,6 @@
---
title: Quick Start
-description: Use the default library to render OpenUI Lang immediately.
+description: Use the OpenUI library to render OpenUI Lang immediately.
---
This is the fastest path: use `openuiLibrary` from `@openuidev/react-ui` and render LLM output with `@openuidev/lang-react`.
diff --git a/docs/content/docs/openui-lang/standard-library.mdx b/docs/content/docs/openui-lang/standard-library.mdx
index f1b264197..2ac59e108 100644
--- a/docs/content/docs/openui-lang/standard-library.mdx
+++ b/docs/content/docs/openui-lang/standard-library.mdx
@@ -1,6 +1,6 @@
---
title: Using the Standard Library
-description: Use the built-in default library from @openuidev/react-ui.
+description: Use the built-in OpenUI library from @openuidev/react-ui.
---
OpenUI ships with a prebuilt `openuiLibrary` for common layouts, forms, content, and charts.
@@ -11,7 +11,7 @@ OpenUI ships with a prebuilt `openuiLibrary` for common layouts, forms, content,
npm install @openuidev/lang-react @openuidev/react-ui
```
-## Render with default library
+## Render with OpenUI library
```tsx
import "@openuidev/react-ui/components.css";
diff --git a/docs/content/docs/openui-lang/syntax.mdx b/docs/content/docs/openui-lang/syntax.mdx
index 949b50e1b..b7ce890b2 100644
--- a/docs/content/docs/openui-lang/syntax.mdx
+++ b/docs/content/docs/openui-lang/syntax.mdx
@@ -38,7 +38,7 @@ cancelBtn = Button("Cancel", "action:cancel", "secondary")
## Rules
- First statement is the entry point.
-- For default library prompts, start with `root = Stack(...)`.
+- For OpenUI library prompts, start with `root = Stack(...)`.
- Arguments are positional, based on Zod key order.
- Optional args can be omitted from the end.
- Forward references are allowed.
diff --git a/docs/lib/layout.shared.tsx b/docs/lib/layout.shared.tsx
index 58740c198..dcd25bc8e 100644
--- a/docs/lib/layout.shared.tsx
+++ b/docs/lib/layout.shared.tsx
@@ -8,7 +8,7 @@ export const gitConfig = {
export const siteConfig = {
githubUrl: `https://github.com/${gitConfig.user}/${gitConfig.repo}`,
- discordUrl: "https://discord.gg/ZeSTyHZTEV",
+ discordUrl: "https://discord.com/invite/Pbv5PsqUSv",
};
export function baseOptions(): BaseLayoutProps {
diff --git a/packages/create-openui-app/src/templates/openui-chat/src/app/page.tsx b/packages/create-openui-app/src/templates/openui-chat/src/app/page.tsx
index db66d864a..b828b1d20 100644
--- a/packages/create-openui-app/src/templates/openui-chat/src/app/page.tsx
+++ b/packages/create-openui-app/src/templates/openui-chat/src/app/page.tsx
@@ -4,9 +4,9 @@ import "@openuidev/react-ui/styles/index.css";
import { openAIMessageFormat, openAIReadableStreamAdapter } from "@openuidev/react-headless";
import { FullScreen } from "@openuidev/react-ui";
-import { defaultLibrary, defaultPromptOptions } from "@openuidev/react-ui/genui-lib";
+import { openuiLibrary, openuiPromptOptions } from "@openuidev/react-ui/genui-lib";
-const systemPrompt = defaultLibrary.prompt(defaultPromptOptions);
+const systemPrompt = openuiLibrary.prompt(openuiPromptOptions);
export default function Home() {
return (
@@ -24,7 +24,7 @@ export default function Home() {
});
}}
streamProtocol={openAIReadableStreamAdapter()}
- componentLibrary={defaultLibrary}
+ componentLibrary={openuiLibrary}
agentName="OpenUI Chat"
/>