For years we have built interfaces around an almost invisible assumption: a human team decides in advance which screens, tables, forms, buttons, and charts will exist. The data can be dynamic, but the visual vocabulary is usually designed before the user arrives.
AI agents make it possible to invert that relationship.
Instead of programming every view ahead of time, we can imagine an application where the user describes a need, a model generates the interface appropriate for that task, and the system executes it under controlled conditions. This idea is usually called generative UI.
ArrowJS is interesting because it tries to turn that idea into a concrete architecture. The project calls itself “the first UI framework for the agentic era” and combines two different proposals:
- an extremely small UI framework close to ordinary JavaScript and TypeScript;
- a sandbox for running dynamically generated UI logic without giving model-authored code direct access to the application’s privileged environment.
The second proposal is the more novel one.
The recent KDnuggets article “Is ArrowJS Really the UI for the Agentic Era?” helped popularize the idea. But the official documentation and experiments built around Arrow reveal something more interesting than “another frontend framework.”
First: ArrowJS tries to be easy for humans and agents
Arrow’s core revolves around a small API built on ordinary TypeScript primitives. Its documentation emphasizes three main functions:
reactive
html
component
It does not require JSX and can use native template literals. It also does not require a framework-specific compilation phase for the basic use case.
A minimal counter looks roughly like this:
import { html, reactive } from '@arrow-js/core'
const state = reactive({ count: 0 })
export default html`
<button @click="${() => state.count++}">
Count: ${() => state.count}
</button>
`
For a human, this reduces the number of extra concepts. For a coding agent, it has another advantage: there is less framework-specific syntax and fewer hidden rules to remember.
Arrow even stresses that its documentation occupies only a small fraction of a large model context window. The implicit thesis matters: a framework an agent can load and reason about almost completely may produce fewer mistakes than one whose semantics depend on a huge collection of conventions, compilers, plugins, and historical exceptions.
That does not prove Arrow produces better code than React in practice. React has a massive advantage in examples, ecosystem, libraries, and training data. But Arrow raises a valid question: should frameworks continue to be designed exclusively for human developers when an increasing share of code will be written by agents?
The decisive piece: @arrow-js/sandbox
This is where ArrowJS becomes much more interesting.
The official @arrow-js/sandbox documentation explains that sandbox() creates a stable host element and boots a QuickJS + WASM VM behind it. Untrusted code runs inside that VM while the host retains ownership of the real DOM.
That distinction matters because the idea is sometimes simplified as Arrow “compiling generated UI to WebAssembly.” That wording can be misleading. A better mental model is:
Generated JS/TS code
│
▼
QuickJS inside a WASM-based VM
│
▼
render/control protocol
│
▼
real DOM owned by the host
Generated code does not need privileged access to the application’s window realm to produce an inline interface.
That separates the approach from two problematic alternatives:
- executing LLM-generated text with
eval()in the main page; - placing every generated interface inside a completely isolated
iframeand accepting the integration limitations.
Arrow aims for a middle ground: isolate the logic while rendering an integrated experience.
The host bridge: capability, not unlimited authority
A generated interface becomes useful when it can query data or perform actions. That immediately raises a security question: what can it actually do?
Arrow lets the host explicitly expose modules through a host bridge.
For example:
sandbox(
{ source: generatedCode },
{},
{
'host-bridge:app': {
getFailedJobs,
retryJob
}
}
)
Inside the sandbox, generated code can import only what the host decided to publish:
import { getFailedJobs, retryJob } from 'host-bridge:app'
The security idea is not “we trust the model to behave.” It is different:
Generated code receives concrete capabilities, not general authority over the application.
If the host does not expose filesystem access, credentials, cookies, SSH, GitHub, or an internal API, the surface should not be able to grant those capabilities to itself.
This resembles capability-based security: possessing an explicit reference to an operation is what allows code to request it.
Example 1: a search interface designed at runtime
Suppose the user writes:
Find quick dinner recipes and let me choose one.
A traditional application needs a prebuilt RecipeSearch screen, with its input box, loading state, cards or table, and selection button.
In a generative UI system, the flow can be different:
User
│
▼
LLM
│ generates Arrow/TypeScript
▼
Sandbox
│
├─ search box
├─ loading state
├─ results
└─ "Choose" button
│
▼
Allowed host tools
├─ searchRecipes(query)
└─ chooseRecipe(id)
The model can decide that cards are the best representation. But the actual recipe search remains the responsibility of the host.
The application can therefore keep authentication, rate limits, data access, and validation under trusted control without pre-programming every possible visual variation.
Summon: a real experiment built around this idea
A particularly useful project for understanding how far the pattern can go is Block Summon.
Summon describes itself as a system for rendering AI-generated UI in an inline Arrow sandbox. Its architecture explicitly separates several concepts:
Surface = generated UI
Host tool = host-owned data source or action
Sandbox = isolated Arrow runtime
SurfacePolicy = what the surface is allowed to request
Diagnostics = traces and events used to debug the run
Its quickstart includes host-backed search, host-owned actions, declarative forms, background work, and approval flows.
There is an important status caveat. The README still describes Summon as beta and under active development, but the GitHub repository is currently marked archived, and the latest visible commits are from June 2026. Summon is therefore best treated as an informative architecture experiment, not as an actively maintained production dependency.
Even so, it demonstrates that the pattern can go much further than a generated counter.
Example 2: publishing requires approval
Imagine an editorial application. The user asks:
Review this draft, summarize its status, and let me publish it if everything looks good.
The agent could generate a surface like:
┌──────────────────────────────────┐
│ Article ready │
│ │
│ 842 words │
│ 3 references │
│ SEO score: 91 │
│ │
│ [ Edit ] [ Publish ] │
└──────────────────────────────────┘
But the fact that the model generated a button named Publish does not mean it owns permission to publish.
A safer architecture keeps the split explicit:
Generated UI
│
│ requests publish(articleId)
▼
Host policy
│
├─ validates parameters
├─ checks permission
├─ asks for human approval
└─ uses real credentials
│
▼
Backend
A useful design rule follows:
Generative UI must not become generative authority.
The interface can propose and request. Authority remains in trusted code.
Example 3: an operations dashboard generated for the current question
Consider a processing system such as a podcast publication pipeline.
The operator asks:
Which publications failed overnight, and which ones can I retry?
A textual answer can list twenty jobs. But the best artifact for that question may be a temporary interface:
Failed publications
┌────────────────────────┬──────────┬─────────────┐
│ Job │ Error │ Action │
├────────────────────────┼──────────┼─────────────┤
│ episode-481 │ timeout │ [ Retry ] │
│ episode-482 │ auth │ [ Details ] │
│ episode-483 │ timeout │ [ Retry ] │
└────────────────────────┴──────────┴─────────────┘
2 look recoverable
[ Retry recoverable jobs ]
Nobody had to create a component called FailedPublicationDashboard ahead of time.
The agent received data and capabilities such as:
get_failed_publications()
retry_publication(id)
Then it decided how to turn those capabilities into a useful interaction.
This illustrates why generative UI may be especially valuable in internal tools. Operators ask highly specific, constantly changing questions. Building a permanent screen for every possible query does not scale.
Example 4: the interface changes as the conversation changes
There is an even more radical possibility.
First the user asks:
Are my eight workers alive?
The agent responds with eight status cards.
Then:
Compare their throughput over the last 24 hours.
Cards are no longer the best representation; a bar chart may be better.
Then:
Show only the two anomalous workers and let me inspect their errors.
The UI can transform again into a diagnostic table.
cards
↓
chart
↓
diagnostics table
↓
worker inspector
The deeper idea is that the interface stops being only the container for the conversation and becomes another response modality of the model.
Today an LLM can return text, code, JSON, or tool calls. In an agentic-first application it could also return an interactive interface specific to the task.
Where do MCP and WebMCP fit?
A natural design is to separate capabilities from presentation.
MCP or similar mechanisms can describe which tools and resources exist:
search_jobs
get_worker_metrics
retry_job
publish_article
Arrow can provide the visual surface that consumes those capabilities.
The mental model becomes:
User
│
▼
Agent / LLM
│
├── decides which tools to use
│
└── generates the appropriate UI
│
▼
Arrow sandbox
│
▼
host-controlled tools
│
▼
real services / data
Tools define what can be done. Generative UI decides how to present it right now.
A sandbox does not remove every risk
It would be a mistake to conclude that WASM automatically makes arbitrary generated code safe.
Several boundaries still need to be defended:
- tool schemas and arguments;
- per-user and per-action permissions;
- CPU, memory, and time limits;
- huge outputs or UIs that try to confuse the user;
- visual phishing inside the host application;
- sensitive actions disguised as harmless controls;
- persistence and replay of generated surfaces;
- contract drift between a saved UI and current host tools.
Summon even included an adversarial scenario for checking attempts to access network, storage, parent context, and unauthorized tools. That exposes a broader point: generative UI security does not end with JavaScript isolation.
The UI itself is also a surface of authority and persuasion.
Does ArrowJS replace React?
That is not the most reasonable conclusion today.
React still has enormous advantages:
- ecosystem;
- libraries and design systems;
- hiring;
- tooling;
- years of documentation;
- a massive amount of examples in model training data.
Agents also keep improving. Part of the argument that complex frameworks are difficult for LLMs may be temporary. Future models may handle hooks, JSX, and toolchains reliably enough that a tiny API matters less.
But that does not invalidate Arrow’s second argument.
React can be excellent for an agent writing ordinary application code and still not, by itself, solve the problem of executing untrusted on-demand UI with an explicit capability boundary.
Those are different problems.
Two theses worth separating
ArrowJS can be evaluated from two perspectives:
A) Agent-friendly framework
Codex / Claude / another agent
│
▼
writes application
│
▼
ArrowJS
And:
B) Runtime for generative UI
User
│
▼
LLM
│ generates UI
▼
QuickJS/WASM sandbox
│
▼
limited host tools
Thesis A is interesting, but it competes directly with gigantic ecosystems.
Thesis B is more novel. It describes an architecture where a model can manufacture the interface needed for a task without receiving general control of the application.
An architecture worth experimenting with
We do not yet know whether ArrowJS will be the framework that popularizes this pattern. The ecosystem remains small, and one of the most interesting experiments built around it, Summon, is already archived.
But the question Arrow raises will probably outlive the framework:
If an agent can decide what information it needs, which tools to call, and which steps to execute, why must the interface used by the human be completely predetermined?
The answer may be a new layer in agentic-first applications:
LLM
│
├── text when text is enough
├── tool calls when it needs to act
└── generated UI when the task needs interaction
The challenge is not merely allowing the model to generate HTML.
It is achieving three properties at the same time:
UI flexibility
+
isolation of generated code
+
host-controlled authority
ArrowJS is interesting because it tries to combine exactly those three pieces.