Open at the newest message, and scroll up for the rest

Fixkamo-internal
Shipped
August 12, 2026 at 10:47 PM UTC
Author
kamo
Commit
f4fead2

Opening a long conversation showed the oldest loaded message first and then travelled down to the present while the member waited. Both chat surfaces scrolled to the bottom only after the list had already painted at the top — ChatBox through rAF → rAF → setTimeout(0), TicketChat through setTimeout(…, 50) — so the trip was guaranteed, and the longer the history the longer it took. The scroll now happens in a layout effect, before paint: the first frame the member sees is the newest message. A one-shot scroll was also not enough to stay there. Attachments, avatars and translated bodies resolve after the rows first render and grow the content under a list already scrolled to the end, leaving the member a little short of the newest message with every image that lands. A ResizeObserver re-pins while they are actually at the bottom, so it can never fight someone reading further up. Beyond that, neither surface had any way back: history was one page of the most recent 100 messages and everything before it was unreachable. Both now page upward as the reader approaches the top, anchoring on the height delta so the prepended block does not drag them through what they were reading. The member chat goes through chat-core's new loadOlder(); the ticket chat, which owns its own fetching, pages on apiRowCount — never messages.length, because an optimistic send would then push the offset past a real message. Smooth scrolling is kept for exactly one case: a message arriving while the member is already following the bottom. That is the only time it describes something rather than delaying it.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing