Brainless UI, and why agents work better against it

This research library uses AI-assisted source research and drafting. Linked sources support product claims; analysis and proposed exercises are our interpretation. Unless an article documents a test and its results, do not read it as a hands-on review or an independently verified benchmark.
A brainless UI component takes data in and renders it. It does not decide whether the user can see the discount. It does not compute the tax. It does not know which of five states the subscription is in. Those answers arrive as props or from a hook, already resolved, and the component's only job is to put them on screen. Old idea, and the usual arguments for it still apply. What is new is that it now changes how well an agent can work in your codebase.
Why a brainless UI helps an agent
Watch an agent write a feature in a component that mixes fetching, business rules, and markup. It has to hold all three in mind and it produces code that looks right and quietly duplicates a rule that already exists two directories away. You end up with the discount logic in three places, agreeing today and diverging in November.
A clearly named shared function gives the agent a searchable place to find the rule. Its own search hits canApplyDiscount before it invents a second one. The component it writes is short enough to review in a glance. And the interesting part gets a unit test, because it is a function taking inputs and returning a value rather than something buried behind a render.
There is a measurement here anyone can run. Take a component over 300 lines with logic inside it, ask for a small change, and count how many lines the diff touches. Do the same with a thin component backed by a separate rules module. Compare both diffs for correctness, duplication and review effort. A smaller diff is useful only if it preserves the required behavior.
What to move out
- Permission and visibility checks.
if (user.role === 'admin' && !org.trialExpired)inside JSX is a bug waiting for a fourth condition. - Currency, date, and unit formatting. One module, tested, shared.
- Derived state. Extract derived state when it expresses a shared or nontrivial rule; a simple local expression can stay beside its use.
- Fetching and caching. The component asks for data. It does not know about retries.
- Complex domain rules that need focused tests.
The honest limits
Taken too far, this produces a wrapper for a wrapper and a codebase where following one value means opening six files. That is worse, for humans and agents both. The line we use: extract when a rule is used twice, or when it has a name your product people would recognise. Not before.
It also does nothing for the genuinely visual bugs. An agent can write a perfect thin component that overlaps a modal on a narrow viewport. No architecture saves you from looking at the screen. Keep a screenshot step in your review for anything user-facing.