Libraries, built-ins, and custom components
An OpenUI Library is the contract between your Agent and your client. It describes the component calls the Agent may write, provides JSON Schema for parsing and prompt generation, and maps each allowed name to a trusted ReactLynx renderer.
This guide covers the default Library, its 26 built-in components, and the process for adding or replacing components.
What a Library contains
Each component definition has four parts:
- a stable OpenUI component
name; - a Zod object schema whose field order defines positional argument order;
- a short
descriptionused in generated prompts; - a trusted ReactLynx
componentimplementation.
createOpenUiLibrary() assembles those definitions into a Library with:
Create the default Library once and keep its identity stable:
Built-in components
createOpenUiLibrary() includes the following components. Their definitions
are also exported from @lynx-js/genui/openui/catalog.
Layout
Content
Buttons
Data display and media
Overlays
Inputs
RadioGroup, Slider, and TextField use @lynx-js/lynx-ui; add that peer
dependency when those components are available to generated UI.
For exact current positional signatures and a live preview, open the OpenUI Catalog. The schema is the source of truth: optional arguments may be omitted only from the right, and named-argument syntax is not supported.
OpenUI component syntax
The order of fields in a component's Zod object is its wire-level positional
argument order. For example, the built-in Stack schema begins with
children, direction, wrap, gap, align, and justify, so this is valid:
This is not valid OpenUI Lang:
Child components are values. They can be declared as named statements or used inline when the parent schema accepts them:
Add a custom component
Install Zod if the application does not already depend on it:
Define a component with a stable name, ordered prop schema, prompt description,
and ReactLynx renderer. Put styles in a CSS class rather than inline style
objects, and wrap visible text in <text>.
The Agent can now emit:
Caller-provided components and groups are appended after the defaults. If a
custom component uses the same name as a built-in, the later custom definition
wins in the components map. Treat that as an intentional override and keep
the prompt-side schema identical.
Render nested component values
If a custom prop accepts child components, use renderNode from the component
render contract. It recursively renders elements, arrays, and primitive values
using the active Library.
Do not call generated functions or evaluate generated strings inside a custom component. Let the OpenUI parser/runtime resolve expressions before props reach the renderer.
Runtime hooks for interactive components
Custom components may use the hooks exported from
@lynx-js/genui/openui:
All of these hooks must run below <OpenUiRenderer>. Interactive components
should honor isStreaming so a user cannot act on a partial model response.
JSON Schema and parser utilities
Use the Library schema for parsing outside the renderer or for inspection:
For streamed text, use createStreamingParser. Its set(fullText) method is
convenient when your UI stores the accumulated response; push(chunk) accepts
only the new delta.
Use the renderer's onParseResult callback when you already render the same
response. That avoids creating a second parser just to inspect root,
stateDeclarations, data statements, or meta diagnostics.
Keep the Agent contract aligned
Adding a component only to the ReactLynx Library is not enough: the Agent must
receive the same name, positional schema, and description. The default prompt
entry is deliberately headless so server code does not import ReactLynx or
component CSS. For custom components, define matching headless prompt entries
and pass them to buildOpenUiSystemPrompt.
See System prompts for the complete CLI and programmatic flow.

