Skip to content

Channels: persistent reply row to stop feed scroll jitter#3324

Draft
adboio wants to merge 1 commit into
mainfrom
posthog-code/channels-persistent-reply-footer
Draft

Channels: persistent reply row to stop feed scroll jitter#3324
adboio wants to merge 1 commit into
mainfrom
posthog-code/channels-persistent-reply-footer

Conversation

@adboio

@adboio adboio commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Problem

In channels, scrolling up through the feed caused visible layout jitter: a message with a human thread would come into view, and a beat later its "N replies" teaser would pop in and push the feed down. The teaser was only mounted once a row scrolled near the viewport, and rendered nothing until its thread fetch resolved — so on the first scroll up from the bottom (rows that have never been fetched) the fetch routinely landed after the row was already visible.

Why: Reported from the Channels (project-bluebird) experience — the late-attaching reply teaser makes scrolling feel unstable, and the existing way to start a thread was hidden in the hover toolbar.

Changes

  • Replace the in-view-gated RepliesRow with a persistent ReplyFooter, rendered at a constant height for every message: the reply teaser once the thread has messages, and a quiet always-visible Reply affordance otherwise. Both states share the same avatar-sized row, so the teaser swaps in after the fetch with no layout shift.
  • The Reply affordance is now always visible, instead of being tucked into the hover toolbar.
  • Add an enabled flag to useTaskThread so only near-viewport rows fetch/poll; off-screen rows show the static affordance and idle, keeping a long feed from polling every row.

Height parity between the two states relies on both using the same AvatarGroup size="xs" row — worth an eyeball in review, but the swap is now a content change, not a 0 → teaser height jump.

How did you test this?

  • pnpm --filter @posthog/ui typecheck — passes.
  • Biome check on the two changed files — clean.
  • No manual/visual run of the app in this environment; the persistent-height claim should be confirmed visually before merge.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Created with PostHog Code

The channel feed only mounted a task's reply teaser once the row scrolled
into the IntersectionObserver band, and the teaser rendered nothing until its
thread fetch resolved. On the first scroll up from the bottom of a feed (rows
that have never been fetched), the fetch routinely landed after the row was
already visible, so "N replies" popped in and shoved the layout down.

Replace the `{inView && <RepliesRow/>}` gate with a persistent `ReplyFooter`
that is always rendered at a constant height: the teaser once the thread has
messages, and a quiet always-visible "Reply" affordance otherwise. Both states
use the same avatar-sized row, so the teaser swaps in after the fetch without
shifting the feed. As a bonus this surfaces a discoverable way into a thread
instead of leaving it in the hover toolbar.

The thread fetch/poll is still gated to near-viewport rows via a new `enabled`
option on `useTaskThread` (passed `inView`), so a long feed does not poll every
row; off-screen rows render the static affordance and idle.

Generated-By: PostHog Code
Task-Id: 5ac91104-20d5-4df7-a82a-3362086bde3a
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit c078844.

@trunk-io

trunk-io Bot commented Jul 9, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant