When building conversational UIs, small interaction details can make a huge difference in how natural the experience feels. Recently, while working on an agentic chat interface, I ran into a deceptively simple requirement:
Whenever the user submits a question, the viewport should scroll to that question, position it neatly at the top, and then let the user read the agent’s response at their own pace.
It sounds straightforward, but the implementation had a few subtle challenges.
Most chat apps scroll new messages to the bottom, where they stack endlessly. For this interface, I wanted something more intentional:
To achieve the temporary space effect, I leaned on modern CSS units like viewport height (vh) and dynamic CSS variables. The idea was simple: whenever the user sends a question, create some space at the bottom of the chat, which effectively pushes their question to the top of the screen.
From a user perspective, this feels intentional: their message takes center stage, while the agent’s answer appears in a comfortable, readable position just below.
The real trick was deciding when to get rid of that artificial space. Leaving it there permanently made the UI look odd, as if something was missing below the messages.
This is where the Intersection Observer API came into play. By watching a small invisible element placed in that whitespace, the system could detect when the user scrolled and the space was no longer visible. At that moment, the extra space was removed - restoring the chat to a normal flow.
This kind of interaction is easy to overlook, but it shapes how people experience a conversational product. Instead of feeling like a chat feed bolted onto a webpage, the interface feels deliberate and respectful of the user’s focus.
By combining viewport-relative layout techniques with scroll-aware cleanup logic, I was able to create a chat UI that feels smooth, intentional, and more human.