How I Actually Ship Generative UI (Without Letting the LLM Write React)
When I heard about Generative UI for the first time, my understanding was that you give an LLM a pro 2026-9-24 05:49:45 Author: hackernoon.com(查看原文) 阅读量:0 收藏

When I heard about Generative UI for the first time, my understanding was that you give an LLM a prompt, and it generates React components on the fly.

That made me interested in Generative UI because it gives us a way to move away from showing the same UI to every user, even when that UI may not be the best fit for what they are trying to do.

With Generative UI, the same data can be presented in different ways depending on the user's intent. One user may need a simple text answer, while another may understand the same data better as a chart, table, or interactive interface.

But the more I thought about letting an LLM generate React components directly on the fly, the more problems I saw.

Testing becomes harder because we cannot expect the model to always generate the same structure or format. There are also concerns around security, accessibility, theming, reliability, and consistency with the application's design system.

Even if the generated component technically works, it may not behave the way the product expects.

One practical way to implement Generative UI is to let the model use trusted components that already exist in the application, instead of generating arbitrary React components directly.

Let the Model Compose the UI, Not Implement It

Imagine an application already has components like:

Card
BarChart
LineChart
Table
Tabs
Button
Alert
Stack

Instead of asking the LLM to write JSX, the model could produce a structured description of what it wants to display.

For example:

{
  "type": "bar-chart",
  "props": {
    "title": "Spending by Category",
    "data": [
      { "category": "Dining", "amount": 620 },
      { "category": "Travel", "amount": 480 },
      { "category": "Groceries", "amount": 410 }
    ]
  }
}

The application can then map that response to a trusted React component.

const componentRegistry = {
  "bar-chart": BarChart,
  table: Table,
  card: Card
};

A small renderer could look like this:

function GenerativeUI({ element }: { element: UIElement }) {
  const Component = componentRegistry[element.type];

  if (!Component) {
    return <Fallback />;
  }

  return <Component {...element.props} />;
}

The model decides what kind of UI is useful.

The application still controls how that component is implemented.

To me, that is a much safer boundary.

The model can decide what the interface needs, but the application still controls which building blocks it can use.

Using Existing Components Does Not Mean the UI Has to Be Fixed

One concern with this approach is that it may sound too restrictive.

If the model can only use existing components, are we really generating UI?

I think we are.

The model does not have to choose one prebuilt screen. It can combine existing components into a new composition.

For example:

Card
 ├── Spending summary
 ├── Bar chart
 └── View transactions action

Or:

Stack
 ├── SummaryCard
 ├── CategoryBreakdown
 └── TransactionTable

The layout itself can still be dynamic.

The model may decide that one request needs a chart and another needs a table. It may also combine multiple components for a more complex answer.

What it should not do, in my view, is invent a completely new chart implementation or generate arbitrary JavaScript and execute it directly in the application.

That gives the model flexibility without giving up control of the UI system.

Not Every Response Should Become a Chart

Generative UI should not mean turning every AI response into a visual interface.

Suppose the user asks:

What was my biggest transaction this month?

If the answer is simply:

Your biggest transaction was $1,240 at Example Airlines.

then plain text is probably enough.

A chart would add complexity without adding much value.

But if the user asks:

Which categories did I spend the most on this month?

then a visual comparison becomes more useful.

A bar chart may communicate the answer faster than a paragraph.

So the goal should not be:

AI response
    ↓
Generate visual UI

It should be closer to:

Understand user intent
    ↓
Choose useful representation
    ↓
Text / Table / Chart / Form / Composite UI

The best UI depends on what the user is trying to understand or do.

Clarify Before Generating

Consider this question:

Where did I spend the most money this month?

That question is ambiguous.

Does the user mean:

  • by category?
  • by merchant?
  • the single largest transaction?

The model could make an assumption and generate a polished chart.

But if that assumption is wrong, the UI may look useful while answering the wrong question.

I think it is better to ask for more context first.

For example:

Do you mean:

• Spending by category
• Spending by merchant
• Your largest individual transaction

Once the user clarifies, the system has enough information to choose a better representation.

This is an important part of Generative UI for me.

It should not replace conversation.

It should use conversation to make better UI decisions.

How Should the Model Choose the Representation?

I do not think the LLM should have unlimited freedom here either.

A production application can define rules and allowed patterns.

For example:

Single fact
    ↓
Text

Exact values across multiple items
    ↓
Table

Category comparison
    ↓
Bar chart

Trend over time
    ↓
Line chart

The model can use those rules together with the user's intent to choose the most useful representation.

For example:

"Compare my spending categories"
        ↓
Bar chart

"Give me the exact amount for each category"
        ↓
Table

"Show the biggest categories and explain the change"
        ↓
Summary + Chart + Explanation

This gives the model some freedom while keeping the output inside predictable application boundaries.

Do Not Expose the Entire Design System

A real application may have hundreds of components.

I do not think the model needs access to all of them.

Instead, I would expose a curated set of components that are useful for AI-generated experiences.

For example:

Card
Table
BarChart
LineChart
Tabs
Alert
Button
Form
Stack

A finance application may also expose domain-specific components:

TransactionTable
SpendingSummary
CategoryBreakdown
AccountCard

A meal-planning application may expose:

MealPlan
RecipeCard
ShoppingList
NutritionSummary

A smaller catalog makes the system easier to reason about and validate.

It also reduces the chance of the model selecting components that were never intended to be used in a generated experience.

The model should get enough building blocks to create useful interfaces, but not the entire internal design system.

The Model Output Should Be Treated as Untrusted Input

Even if the model only produces structured UI descriptions, I would not render them blindly.

The output should still be validated.

For example:

const result = uiSchema.safeParse(modelOutput);

if (!result.success) {
  return fallbackResponse;
}

If the model asks for an unsupported component, the application should fail safely.

const Component = componentRegistry[element.type];

if (!Component) {
  return <FallbackMessage />;
}

The fallback could be plain text, an error message, or another attempt using supported components.

The important point is that model output should be treated as data, not trusted application code.

This also keeps the application as the security boundary.

The model may suggest UI or actions, but normal application permissions and validation should still apply.

Not Every User Action Needs Another Model Call

Suppose the generated UI looks like this:

Spending by Category

Dining       $620
Travel       $480
Groceries    $410

[View Dining Transactions]
[Explain Dining Increase]

These two actions look similar in the interface, but they should not necessarily be handled the same way.

If the user clicks:

View Dining Transactions

the application already knows what to do.

It can filter the current data or make a normal API call.

function viewDiningTransactions() {
  filterTransactions({
    category: "Dining"
  });
}

There is no reason to send this back through the LLM.

But if the user clicks:

Explain Dining Increase

that requires interpretation.

That is a good reason to involve the model again.

function handleAction(action: Action) {
  if (action.type === "view-transactions") {
    filterTransactions(action.category);
    return;
  }

  if (action.type === "explain-spending") {
    sendToAgent(action);
  }
}

This gives me a simple rule:

Use the LLM when intelligence is needed, not just because the UI was generated by AI.

Deterministic actions should remain deterministic.

That makes the application easier to test and keeps unnecessary model calls out of normal UI interactions.

The Architecture I Would Start With

Putting all of this together, the architecture I would start with looks something like this:

User
  ↓
LLM / Agent
  ↓
Understand intent
  ↓
Structured UI Spec
  ↓
Schema validation
  ↓
Component Registry
  ↓
Trusted React UI

The model might return something like:

{
  "elements": [
    {
      "type": "text",
      "content": "Dining was your highest spending category."
    },
    {
      "type": "bar-chart",
      "props": {
        "title": "Spending by Category",
        "data": [
          { "category": "Dining", "amount": 620 },
          { "category": "Travel", "amount": 480 },
          { "category": "Groceries", "amount": 410 }
        ]
      }
    }
  ]
}

The application validates that structure and renders only supported components.

This still feels like Generative UI to me.

The model is deciding what experience should appear next, but it is not bypassing the frontend architecture.

The Hard Part Is Not Rendering React

The actual React rendering is probably one of the easier parts.

Mapping:

{
  "type": "bar-chart"
}

to:

<BarChart />

is straightforward.

The harder questions are around the boundaries.

What if the model requests an invalid component?

What if the props do not match the schema?

What if the user does not have permission to perform an action?

What if the selected visualization is valid but misleading?

How do we test different generated combinations?

How do we guarantee accessibility?

How do we version the UI schema as components evolve?

How do we decide which components should be available to the model?

These are the parts that make Generative UI interesting to me.

It is not just an LLM generating React.

It is a new interaction between a probabilistic model and a deterministic frontend system.

Where My Thinking Landed

My initial understanding of Generative UI was simple:

Give an LLM a prompt and let it generate React components on the fly.

I still like the idea of dynamically adapting the interface to the user, but I do not think unrestricted component generation is the right production boundary.

I would rather let the model decide what kind of experience the user needs and let the application control the actual components, validation, permissions, accessibility, and execution.

The model is not replacing the frontend.

It is helping decide what frontend experience the user needs next.

And to me, that is much more interesting than simply asking an LLM to write React.


文章来源: https://hackernoon.com/how-i-actually-ship-generative-ui-without-letting-the-llm-write-react?source=rss
如有侵权请联系:admin#unsafe.sh