ikkachar.dev
All writing
3 min read

The chat UX is the product, not the model

shadcn calls it scroll engineering. It is bigger than that. Users don't churn on your model, they churn on the chat UX around it.

Users don't churn over your model. They churn over the chat experience around it. Same model, two products: one feels alive, the other fights you on every scroll. The difference is craft nobody puts on the roadmap.

shadcn just published 15 rules for a great streaming chat experience. They are good. Read together, they point at something bigger than scroll.

The one rule under all fifteen

Every item on that list reduces to a single principle: never move the reader against their intent.

Auto-scroll by default is the bug, not the feature. Follow the stream only while the reader is following it. The moment they scroll up, select text, open a link, or touch the keyboard, that is intent. Stop moving. The interface should never drag attention somewhere the reader did not ask to go.

Scroll is the visible tip

shadcn calls it scroll engineering. Scroll is just the part you can see. The same principle governs the whole turn.

Keep enough of the previous answer on screen that people know where they are. Start each new turn near the top so it can be read from the beginning. Pace the stream so it is fast but not frantic. Let new content arrive offscreen without yanking the viewport. This is layout under motion, and most chat UIs get it wrong because they were built as a div that appends text.

The hard part is interruptions

Streaming is easy when nothing goes wrong. The craft shows up when it does.

Stop, retry, regenerate, branch, error. None of those should steal the reader's position. Reopening a saved conversation should land on the last meaningful turn, usually the user's last message, not the absolute bottom of a 200-message log. Images load, markdown expands, code blocks render, older messages page in above - and through all of it the reader should keep their place. That is the line between an app that respects attention and one that resets it.

Even the terminal fights this

This is not a web problem. It is a chat problem, and it follows the format anywhere chat goes.

Claude Code runs in a terminal and fights the exact same battle: scrollback you can trust, a way to jump back to the latest output, keeping your place while tokens stream in, announcing what is happening without drowning you in noise. No React, no virtualized list, same discipline. The surface changes. The craft does not.

Why nobody staffs it

Here is why this matters more than it looks. Everyone now rents the same frontier models. Your competitor is one API key away from the same intelligence you have. The model is not where you win.

The chat experience around the model is the part you own and the part users feel on every single turn. It is also the part nobody assigns an owner. There is a prompt engineer, a model eval, a RAG pipeline - and the scroll position gets handled by whoever touched the component last.

A bigger model won't save you here, and your homepage won't either if the product behind it jitters.

Screenshot this

Users don't churn on your model. They churn on your scrollbar.

The model is rented. The chat is yours. Build it like it matters, because it is the only part of the stack your users actually touch.

Did this resonate?

Get new essays by email

Field notes on AI-native products, straight to your inbox. No spam, unsubscribe any time.