Every screen you have ever designed hides one assumption. You knew, ahead of time, what would be on it. Generative UI takes that away. Once it is gone, most of what we call design has to be rebuilt from scratch.
Jakob Nielsen called AI the first new way of using computers in sixty years. For the first time, users say what they want, not the steps to get there. He called this intent-based design: you state the outcome. But here is the part nobody quotes. If the user names an outcome, someone still has to build the screen that delivers it. And that someone is no longer a person drawing rectangles.
AI is introducing the first new user-interface paradigm in 60 years. Users tell the computer the desired outcome, not how to do it.
From a drawn screen to a computed one

The old way was a relay race. A designer drew a screen. An engineer rebuilt it in code. A server sent data, and the browser turned it into pixels. Every possible version had to be planned in advance. Empty state, loading state, error state, twelve versions of one table: all drawn, all shipped, most never seen.
Generative UI cuts the relay short. The AI takes the request, picks from a registry, and streams the finished screen down. The registry is just the box of parts the AI is allowed to use. React Server Components made this work. What travels across the network is no longer raw data, it is ready-made screen pieces. Your app stops growing with every new view, because views are built the moment someone asks.
- Designer draws every state by hand
- Engineer rebuilds the drawing in code
- Server ships data, browser builds fixed pixels
- Every version planned in advance
- A new view means new code in the app
- Designer builds the parts and the rules
- AI picks parts from a trusted box
- Server streams ready-made screen pieces, not data
- Screens built the moment someone asks
- A new view is a new arrangement, no new code
What actually forces the model to obey
A language model does not draw a screen. It writes a list of choices: this component, these values, in this order. The registry only works because something stops the model from writing anything else. That something is constrained decoding.
Constrained decoding is a filter on the model's output. A model builds its answer one token at a time, and at each step it ranks every token it could write next. Constrained decoding blanks out any token that would break your schema before the model picks. So it can choose metricCard or lineChart, because both are in the box. It cannot choose a tag you never defined, because that token is not on the menu. A dropdown does the same thing for a person: you can only pick options that exist. This is a dropdown for the machine.
Researchers call the general technique grammar-constrained decoding. You hand the model a grammar of what counts as valid output, and it can only produce output that fits. The Vercel AI SDK does this with a function called generateObject, checked against a schema you write. The result is not the model trying to behave. It is the model being unable to misbehave.
That is the entire safety story, and it is worth being blunt about why. Freeform output means the model could emit any markup, any script, any layout. You would be trusting a text generator with your document. A fixed registry means the worst it can do is choose a wrong part from a set you built and tested. The blast radius shrinks from anything to your own components.
The catch is that a valid choice is not the same as a good one. The schema guarantees the model picks real parts with real values. It does not guarantee the arrangement makes sense. The model can ask for eleven metric cards in a row, a bar chart for a single number, or a card nested inside a card the design never tested. Every part is legal. The screen is still broken. The registry constrains the vocabulary, not the taste. This is why composition rules matter as much as the schema. The maxSiblings and nestable limits are how you turn valid tokens into valid screens. Without them you have taught the model your words but not your grammar.
The registry is the design work
Most teams miss this part. The AI can only use the parts you have built. So your component library stops being a nice-to-have and becomes the whole rulebook. It sets the limit on every screen your product can ever show. Think of Lego. You can build endless things, but only from the bricks in the box. Nathan Curtis said a design system is a product that serves products. Here it is more like a box of bricks: a small set of parts, endless builds.
So the payoff moves. Ship one more beautiful screen and you have added one screen. Add one good building block and you have added every future screen that block can be part of. That is a very different return on the same day of work.
Three things break immediately
- 01Layout stability. If the screen is built on the spot, content shows up in any order and any amount. Fixed heights, locked columns, and pixel-perfect spacing stop being promises and become wishes.
- 02Learnability. Jakob's Law says people spend most of their time on other apps, so they expect yours to work the same way. A screen that rebuilds itself every time gives them no habit to lean on. So you have to anchor the familiar things instead: navigation, colour, motion, and type.
- 03Accountability. When a person designs a screen, a person owns that call. When the AI builds it, you have to record the trail on purpose: what was shown, from which part, on what data, and how sure it was.
What replaces the mockup
Not nothing. The thing you hand over just changes shape. Instead of a screen you ship three things. Building blocks with firm rules. Layout rules that say what can sit next to what. And fallbacks that say what the screen becomes when the AI is unsure or wrong.
| Rule | What it locks down | Why the AI needs it |
|---|---|---|
| Schema | Allowed inputs and their limits | Blocks bad data before it shows |
| Confidence | How sure the data is | Lets the part show doubt on screen |
| Limits | Neighbours, nesting, how many | Blocks layouts that break |
| Fallback | What shows when data is thin | Guarantees a clean empty state |
| Failure | What happens on bad or missing input | Stops silent breakage |
export const registry = {
metricCard: {
render: MetricCard,
schema: z.object({
label: z.string().max(48),
value: z.number(),
delta: z.number().optional(),
confidence: z.enum(["high", "medium", "low"]),
}),
// Composition rule: never more than 4 in a row,
// never nested inside another card.
constraints: { maxSiblings: 4, nestable: false },
},
} satisfies RegistryNotice that confidence is required, not a nice extra. Here, how sure the AI is counts as data. If it is guessing, the part must be able to show that on screen. You make that call once, in the building block, not a thousand times across screens.
Most generative UI is not generative
Here is the honest part most posts skip. Almost everything shipping under the name generative UI today is conditional rendering with a language model picking the branch. You built five components. The model reads the request and calls one of them with some arguments. That is a switch statement with a smarter switch. Useful, shippable, safe. But the layout was decided by you, in advance, the moment you wrote the five branches.
I do not say this to knock it. The branch-picking version delivers most of the value and carries almost none of the risk, which is exactly why it is what ships. If you only need the model to route a request to the right pre-built view, do that and stop. Do not reach for anything more generative than the problem needs.
Genuinely generative UI would mean the model composing arrangements you did not spell out. It would choose how to group, nest, and order parts from the shape of the data, not fill slots in a layout you already drew. Give it a list, a total, and three categories, and it decides a summary row above a grouped table is the right structure, with no branch written for that case. That is a real step up, and it is rare, because the moment the model owns structure you inherit every layout it can invent, including the ones you never tested.
- You wrote every layout in advance
- Model routes the request to one of them
- Safe, shippable, most of the value
- A new layout means new code
- You wrote the parts and the rules
- Model decides structure from the data's shape
- Rare, riskier, where the research still is
- A new layout means no new code
So the ladder has three rungs. Pick a component, which everyone does. Fill a slot, which is common. Compose a novel layout from primitives, which is rare and where the real research sits. Know which rung you are on. Most products should stand happily on the second.
The uncomfortable part
Generative UI is genuinely worse than a hand-drawn screen for any problem you already understand. If the task is small, repeated, and clear, like a checkout, a settings page, or a login, a fixed screen wins on speed, trust, and cost. Bret Victor's point in Magic Ink still holds. Most software problems are really information problems. The best answer is often a still screen that answers the question before you ask it.
So the real skill is not building generative screens. It is knowing where the line is. Generation earns its keep when the problem is too big to list out. Think open exploration, rare support cases, or free-form making. Anywhere the number of possible questions is bigger than the number of screens you could ever draw.
Where this idea came from
None of this is new, only newly aimed at screens. Restricting a generator to legal moves is how a compiler works. Source code is valid only if it fits the grammar of the language, and the parser throws out everything else. It is how a web form works. A country dropdown offers the ten you support and no eleventh. Model function calling brought the same discipline to language models by making them return arguments that fit a named schema instead of free prose. Generative UI is that lineage pointed at layout. The parts are the vocabulary, the composition rules are the grammar, and the model is a fast, slightly unreliable author working inside both.
What to do on Monday
Do not start by building a generative screen. Start by writing the rules for one component you already ship, the way the code block above does. Its inputs, their limits, its confidence field, its fallback, and its composition rules. If you cannot fill every field in plain words the model could act on, the problem is the component, not the model. Put that one part in the registry, let the model choose it for a single narrow request, and watch what it does at the edges. You will learn more from one constrained part in real use than from a demo that generates a whole page and impresses nobody twice.