Skip to content

fix: keep the review sidebar scroll steady when selecting a thread - #4

Closed
petergaultney wants to merge 2 commits into
No-Instructions:mainfrom
petergaultney:fix/sidebar-scroll-after-rerender
Closed

petergaultney wants to merge 2 commits into
No-Instructions:mainfrom
petergaultney:fix/sidebar-scroll-after-rerender

Conversation

@petergaultney

Copy link
Copy Markdown
Contributor

🍋: drafted by a lemon from the debugging session; Peter reviewed the behavior in Obsidian.

On 0.2.1, clicking a commented highlight in the note, or a card in the sidebar, made the sidebar flash and end up somewhere other than the clicked thread - usually the top of the list. In a note with ~10 threads this made replying a two-step hunt: click the card, lose it, scroll to find it again.

Measured over CDP in Obsidian (Electron --remote-debugging-port), wrapping render() and sampling contentEl.scrollTop, the cause is that every render() rebuilds the sidebar with root.empty(). Emptying the scroller collapses it and resets scrollTop to 0 before the new content exists. From there two things went wrong:

  • One click renders twice (locateItem -> locateReviewRange -> refreshReviewSidebars, then locateItem's own render()). The lastScrolledItemId guard skipped the re-scroll on the second render because the same card was still selected, so the list stayed at 0. That's the "scrolls to the top".
  • Even with a single render, scrollIntoView({block: "nearest"}) from 0 parks the card at the bottom edge of the viewport rather than where it was, so every click moved the list by a few hundred pixels.
  • The scroll target was the first card in document order that rendered as selected. A card under the editor cursor also renders as selected, so it often won over the card the user had just picked. That's the "unpredictable places".

Changes

  • renderContent saves scrollTop before root.empty() and restores it after the body is built, then calls scrollIntoView on the selected card. The viewport only moves when the selected card is actually out of view. lastScrolledItemId is gone; nearest is already a no-op for a visible card.
  • The scroll target prefers selectedItemId (the card the user picked) over the cursor-derived selection.
  • New: the picked card gets critic-card-current, which colors its spine and border with --interactive-accent. The cursor's card keeps the existing softer critic-card-selected look, so the two are distinguishable when both are shown.

Measured after the change: clicking a card positioned 20px from the top leaves scrollTop unchanged and the card at 20px; clicking an anchor in the note scrolls the sidebar so the matching card is in view, with selectedItemId and the scrolled-to card agreeing.

No changelog file in the repo, so none updated. 178 unit tests pass.

Selecting a thread, from a card or from its anchor in the note, rebuilds
the sidebar with root.empty(), which collapses the scroller and resets
scrollTop to 0. The rebuilt list then either stayed at the top (the
lastScrolledItemId guard skipped the re-scroll when the same card was
selected twice in one click) or parked the card at the bottom edge of
the viewport (scrollIntoView "nearest" from 0). Restore scrollTop after
the rebuild so the viewport only moves when the selected card is
actually out of view.

Scroll to the card the user picked, not the first selected-looking card
in document order: a card under the editor cursor also renders as
selected, and used to win the scroll target.
Two cards can render as selected at once: the one the user clicked (or
reached from its anchor in the note) and the one under the editor
cursor. Give the picked card an accent-colored spine and border so it
stands apart from the cursor's card.
@petergaultney
petergaultney marked this pull request as ready for review September 19, 2026 14:32
@dtkav

dtkav commented Sep 25, 2026

Copy link
Copy Markdown
Member

Thanks, Peter. I incorporated this work into Relay Comments 0.3.0 and credited you in the release notes.

  • 6ec85e4 includes the stable-scroll and explicit selected-card targeting changes, adapted around the Canvas and external-comment support that landed at the same time.
  • 03160c4 includes the selected-card accent.
  • 85cb7d4 adds a follow-up fix and regression coverage for resetting scroll when switching notes.

These changes are available in the 0.3.0 release. I took the changes onto main rather than merging this branch directly because the surrounding sidebar code had changed in parallel. I’m closing this as incorporated. Thanks again for the careful diagnosis and implementation.

@dtkav dtkav closed this Sep 25, 2026
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.

2 participants