v0.1

The original OpenUI Lang specification for declarative UI generation in chat responses.

This is the v0.1 specification, the original language for generating static UI from LLM output. For the latest version with reactive state, data queries, and interactive apps, see v0.5.

OpenUI Lang is the output format the LLM generates. It is a compact, declarative, line-oriented DSL designed specifically for streaming and token efficiency.

While you rarely write this language manually, understanding the syntax is helpful for debugging raw LLM outputs or building custom parsers.

Syntax Overview

The language consists of a series of assignment statements. Every line binds a unique identifier to an expression.

root = Root([header, chart])           // 1. Entry Point
header = Header("Q4 Revenue", "YTD")   // 2. Component Call
chart = BarChart(labels, [s1, s2])     // 3. Forward Reference
labels = ["Jan", "Feb", "Mar"]         // 4. Data Definition
s1 = Series("Product A", [10, 20, 30])
s2 = Series("Product B", [5, 15, 25])

Core Rules

  1. One statement per line: identifier = Expression
  2. Root Entry Point: The first statement must assign to the identifier root (or call the Root component). If missing, nothing renders.
  3. Top-Down Generation: Statements are generally written top-down (Layout -> Components -> Data) to maximize perceived performance during streaming.
  4. Positional Arguments: Arguments are mapped to component props by position, defined by the order of keys in your Zod schema.

Expressions & Types

OpenUI Lang supports a strict subset of JavaScript values.

TypeSyntaxExample
Component CallType(arg1, arg2)Header("Title", "Subtitle")
String"text""Hello world"
Number123, 12.5, -542
Booleantrue / falsetrue
Nullnullnull
Array[a, b, c]["Jan", "Feb", "Mar"]
Object{key: val}{variant: "info", id: 1}
ReferenceidentifiermyTableData

Component Resolution

The parser maps Positional Arguments in OpenUI Lang to Named Props in React using your Zod definitions.

The Mapping Logic

The order of keys in your z.object schema defines the expected argument order.

1. The Schema (Zod)

const HeaderSchema = z.object({
  title: z.string(), // Position 0
  subtitle: z.string().optional(), // Position 1
});

2. The Output (OpenUI Lang)

h1 = Header("Dashboard", "Overview")

3. The Result (React Props)

{
  "title": "Dashboard",
  "subtitle": "Overview"
}

Critical implications for component design

  • Key order in z.object is the API contract. Changing key order breaks all existing LLM outputs.
  • Required props must come before optional props in the schema, since trailing optional args can be omitted.
  • The LLM learns positions from the auto-generated system prompt. If the prompt and schema disagree (e.g., after a schema change without regenerating the prompt), output will be garbled.

Optional Arguments

Optional arguments (trailing) can be omitted.

// Valid: subtitle is undefined
h1 = Header("Dashboard")

Streaming & Hoisting

OpenUI Lang allows Forward References (Hoisting). An identifier can be used as an argument before it is defined in the stream. This is critical for progressive rendering.

How it works

root = Root([table]) // "table" is referenced here...
// ... (network latency) ...
table = Table(rows)  // ...but defined here.
  1. Step 1: The renderer parses root. It sees table is undefined. It renders a Skeleton/Placeholder for the table.
  2. Step 2: The table definition arrives. The renderer updates the React tree, replacing the skeleton with the actual Table component.
  3. Step 3: rows arrives → Table fills in with data.

Complete Syntax Example

A complex example showing nesting, arrays, and mixed types.

root = Root([nav, dashboard])
nav  = Navbar("Acme Corp", [link1, link2])
link1 = Link("Home", "/")
link2 = Link("Settings", "/settings")

dashboard = Section([kpi_row, main_chart])
kpi_row   = Grid([stat1, stat2])
stat1     = StatCard("Revenue", "$1.2M", "up")
stat2     = StatCard("Users", "450k", "flat")

main_chart = LineChart(
  ["Mon", "Tue", "Wed"],
  [Series("Visits", [100, 450, 320])]
)

On this page