mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

Dev Tools

OpenUI Lang: How a 67% Token-Efficient Streaming Format Turns LLM Output Into Structured UI Components

A compact, streaming-first language that lets models generate structured UI components with 67% fewer tokens than JSON, framework-agnostic rendering.

Source: github.com
OpenUI Lang: How a 67% Token-Efficient Streaming Format Turns LLM Output Into Structured UI Components

Most agent interfaces still treat LLM output as text that gets parsed into UI after the fact. OpenUI Lang flips that: it is a compact, streaming-first serialization format that lets models generate structured UI components directly. The format uses 67% fewer tokens than JSON, supports framework-agnostic rendering (React, Vue, Svelte, Angular), and handles partial output during streaming. This matters because agent cost and latency scale with token count, and real-time UI generation requires parseable incremental state.

OpenUI is trending at rank 10 for TypeScript on GitHub with 12,787 stars. It ships a core parser, framework runtimes, built-in component libraries (charts, forms, tables, layouts), and prompt templates that teach models to emit OpenUI Lang instead of JSON or Markdown.

Why Token Efficiency Matters for Agent UI

When an agent generates a UI component, JSON serialization is verbose. A simple card with a title, description, and button might require 200+ tokens in JSON. OpenUI Lang compresses that to around 66 tokens by using a terse, whitespace-sensitive syntax that omits redundant keys and brackets.

Token cost example:

FormatTokensReduction
JSON200baseline
OpenUI Lang6667%

This reduction compounds across multi-turn conversations. If an agent generates 10 UI updates per session, the token savings directly reduce API cost and latency. For streaming output, fewer tokens also mean faster time-to-first-render.

OpenUI Lang Syntax

OpenUI Lang uses indentation and shorthand to define components. Here is a minimal example:

Card
  title: "System Status"
  description: "All services operational"
  Button
    label: "View Details"
    onClick: showDetails

This compiles to a framework-specific component tree. The parser recognizes component names (capitalized), properties (lowercase with colons), and nested children (indented blocks). No closing tags, no brackets, no quotes unless the value contains special characters.

Key syntax rules:

  • Component names are capitalized and start a block
  • Properties are lowercase key: value pairs
  • Children are indented under the parent
  • Strings with spaces or special characters use quotes
  • Arrays use comma-separated values on one line or indented items

The parser is streaming-aware. It can render partial trees as tokens arrive, which is critical for real-time agent interfaces where users see UI build incrementally.

Framework-Agnostic Rendering

OpenUI Lang compiles to an intermediate representation (IR) that framework runtimes consume. The core parser emits a tree of nodes with component types, properties, and children. Each framework runtime maps those nodes to native components.

Rendering flow:

  1. Model emits OpenUI Lang tokens
  2. Core parser builds IR tree (streaming or batch)
  3. Framework runtime (React, Vue, Svelte, Angular) maps IR nodes to components
  4. UI renders in the target framework

The framework runtimes are thin adapters. React uses JSX, Vue uses render functions, Svelte uses component constructors, Angular uses dynamic component loading. The IR is the boundary: everything upstream is framework-agnostic, everything downstream is framework-specific.

Component registration:

Each runtime maintains a component registry. You register custom components by name:

import { registerComponent } from '@openui/react';

registerComponent('CustomCard', CustomCardComponent);

When the parser encounters CustomCard in OpenUI Lang, the runtime looks up the registered component and renders it. This lets you extend the built-in library without modifying the core parser.

Streaming Parser Design

The streaming parser is a state machine that processes tokens incrementally. It maintains a stack of open components and appends properties or children as tokens arrive. When a component block closes (dedent or end-of-stream), the parser emits a render event.

Parser states:

  • Idle: Waiting for a component name
  • Component: Reading properties and children
  • Property: Reading a key-value pair
  • Value: Reading a property value (may span multiple tokens)
  • Child: Recursively parsing a nested component

The parser handles partial input gracefully. If the stream cuts off mid-property, it emits the partial tree and marks the incomplete node. The UI can render what exists and show a loading indicator for the incomplete section.

Error recovery:

If the model emits malformed OpenUI Lang (mismatched indentation, missing colons, invalid component names), the parser attempts to recover by:

  • Treating unrecognized lines as text content
  • Auto-closing components at dedent boundaries
  • Logging warnings without halting the stream

This is important because models are not perfect. A strict parser would fail on minor syntax errors, but a lenient parser keeps the UI usable even when the model output is slightly off.

State Synchronization and Interactivity

OpenUI Lang is declarative. It describes UI structure, not behavior. Interactive components (buttons, forms, inputs) need event handlers, which OpenUI Lang references by name:

Button
  label: "Submit"
  onClick: handleSubmit

The handleSubmit function must exist in the application context. The framework runtime binds the named handler to the component. This keeps the serialization format stateless while allowing rich interactivity.

State management options:

  • Local state: Components manage their own state (e.g., form inputs)
  • Context state: Shared state via React Context, Vue provide/inject, etc.
  • Agent state: The agent maintains state and regenerates UI on updates

For agent-driven UIs, the third option is common. The agent holds the canonical state and emits new OpenUI Lang when state changes. The UI re-renders from the new tree. This avoids client-side state drift but requires efficient re-rendering (React’s reconciliation, Vue’s reactivity, etc.).

Built-In Component Libraries

OpenUI ships component libraries for common UI patterns:

  • Charts: Line, bar, pie, scatter (powered by Recharts or similar)
  • Forms: Input, select, checkbox, radio, textarea
  • Tables: Sortable, filterable, paginated data grids
  • Layouts: Grid, flex, stack, card, modal

These components are pre-registered in the framework runtimes. The agent can reference them directly in OpenUI Lang without custom registration:

LineChart
  data: salesData
  xAxis: month
  yAxis: revenue

The built-in libraries reduce the need for custom components in simple cases. For complex UIs, you register custom components and teach the model to use them via prompt engineering.

Prompt Engineering for OpenUI Lang

To get models to emit OpenUI Lang, you include the syntax rules and component library in the system prompt. OpenUI provides prompt templates that describe the format and list available components.

Example prompt snippet:

You generate UI using OpenUI Lang. Use indentation for nesting.
Available components: Card, Button, Input, LineChart, Table.
Example:
Card
  title: "Dashboard"
  Button
    label: "Refresh"
    onClick: refresh

The model learns the syntax from examples. For complex UIs, you provide few-shot examples that demonstrate nested components, arrays, and conditional rendering.

Prompt optimization:

  • Include only the components the agent needs (reduces token count)
  • Show examples of common patterns (forms, dashboards, modals)
  • Specify property types (string, number, boolean, array)

The prompt is part of the infrastructure. You version it alongside the component library and update both when you add new components.

Deployment Shape

OpenUI runs in two modes:

  1. Client-side rendering: The agent emits OpenUI Lang, the browser parses and renders it
  2. Server-side rendering: The server parses OpenUI Lang and sends HTML (or framework-specific SSR output)

Client-side rendering is simpler and works well for interactive agents. The browser receives a stream of OpenUI Lang tokens, parses them incrementally, and updates the DOM. This requires the framework runtime and component library to be bundled in the client.

Server-side rendering is useful for static or cacheable UIs. The server parses the OpenUI Lang, renders the component tree to HTML, and sends it to the client. This reduces client-side JavaScript but loses streaming interactivity.

Hybrid approach:

Some deployments use server-side rendering for the initial page load and client-side rendering for agent updates. This balances performance (fast first paint) with interactivity (streaming updates).

Observability and Debugging

Debugging generative UI is hard because the model output is non-deterministic. OpenUI provides logging hooks at the parser and runtime levels:

  • Parser logs: Token stream, IR tree, syntax errors
  • Runtime logs: Component registration, render events, event handler calls

You can enable verbose logging to see exactly what the parser received and how it was interpreted. This is critical when the model emits unexpected OpenUI Lang.

Common failure modes:

FailureSymptomFix
Mismatched indentationComponents render flatAdd indentation examples to prompt
Unregistered componentComponent not found errorRegister component or remove from prompt
Invalid property valueProperty ignored or errorSpecify property types in prompt
Stream cuts off mid-blockPartial UI rendersHandle incomplete state in UI

For production deployments, you log parser errors and model output to a monitoring system (Datadog, Sentry, etc.). This lets you track how often the model emits malformed OpenUI Lang and tune the prompt accordingly.

Security Boundaries

OpenUI Lang is declarative and does not execute arbitrary code. Event handlers are referenced by name, not defined inline. This prevents injection attacks where the model emits malicious JavaScript.

Security considerations:

  • Component whitelist: Only registered components can render
  • Property validation: Framework runtimes validate property types
  • Event handler binding: Handlers must exist in the application context
  • Content sanitization: Text content is escaped by the framework (React, Vue, etc.)

The main risk is prompt injection, where a user tricks the model into emitting OpenUI Lang that references unintended components or handlers. You mitigate this by:

  • Validating user input before passing it to the model
  • Limiting the component library to safe, non-destructive components
  • Auditing event handlers to ensure they do not perform dangerous actions

When to Use OpenUI Lang

OpenUI Lang is a good fit when:

  • You need real-time UI generation from an agent
  • Token cost and latency matter (high-frequency updates, large UIs)
  • You want framework-agnostic serialization (multi-platform support)
  • You have a constrained component library (dashboards, forms, reports)

It is not a good fit when:

  • You need pixel-perfect custom layouts (use a design tool or hand-coded components)
  • The UI is static and does not change based on agent output
  • You already have a robust JSON-based UI generation pipeline

The 67% token reduction is the main draw. If your agent generates UI frequently, the cost savings add up. If UI generation is rare, the overhead of learning OpenUI Lang may not be worth it.

Technical Verdict

OpenUI Lang is infrastructure for agent-to-UI communication. It solves the token efficiency problem by using a compact, streaming-first format. The framework-agnostic design means you can deploy the same agent across React, Vue, Svelte, and Angular without rewriting the UI generation logic.

Use it when you need real-time, cost-efficient UI generation from an agent. Avoid it when you need full design control or when UI generation is infrequent. The streaming parser and built-in component libraries reduce integration effort, but you still need to prompt-engineer the model to emit valid OpenUI Lang.

The project is actively maintained (12,787 stars, trending on GitHub) and has a growing ecosystem. If you are building agent interfaces that go beyond terminal output, OpenUI Lang is worth evaluating.