Skip to content

Improved comments threading UI#27962

Merged
kevinansfield merged 9 commits into
mainfrom
better-comments-ui-threading-styles-wip
May 19, 2026
Merged

Improved comments threading UI#27962
kevinansfield merged 9 commits into
mainfrom
better-comments-ui-threading-styles-wip

Conversation

@weylandswart
Copy link
Copy Markdown
Contributor

@weylandswart weylandswart commented May 19, 2026

closes https://linear.app/ghost/issue/BER-3649/

  • Improved the visuals of threads in comments-ui, replacing rails with elbows
  • Adjusted position of reply form so it opens directly underneath the comment you are replying to

weylandswart and others added 5 commits May 18, 2026 14:49
no issue

Thread connector styling needs sibling position data from the decorated reply graph so recursive rendering does not pass presentation state through every layer.
no issue

The reply connector styling is a presentation concern, so naming it as a layout variant keeps it separate from comment parentage and graph structure.
no issue

The new connector treatment belongs with the commentsThreads experiment, so flat replies keep their existing layout when the labs flag is disabled.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

Review Change Stack

Walkthrough

This PR refactors the threaded comment UI system by introducing sibling position metadata to the thread graph and propagating layout control props throughout the component hierarchy. The thread graph builder now enriches ThreadedReply objects with siblingIndex and siblingCount fields via a new assignThreadMetadata traversal. AnimatedComment, CommentComponent, and Replies now accept and propagate layoutVariant, isLastSibling, and useThreading props. CommentLayout is significantly refactored to accept injected replies and replyForm props, render them inline, and apply conditional styling for threaded vs non-threaded modes, including vertical connector decorations. Both PublishedComment and UnpublishedComment move reply rendering inside CommentLayout. Form components now support a threadedLayout prop to adjust spacing and avatar positioning. Tests validate sibling metadata assignment and threaded reply-form placement behavior.

Possibly related PRs

  • TryGhost/Ghost#27847: Implements the initial threaded-comments UI by extending Comment/CommentComponent and reply rendering to accept threading-related props and propagate them through the comment hierarchy in apps/comments-ui/src/components/content/.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title 'Improved comments threading UI' directly and clearly summarizes the main change across the entire changeset, which refactors comment rendering to support better threading UI with layout controls, connector styles, and elbow-style visual improvements.
Description check ✅ Passed The pull request description accurately relates to the changeset, describing the visual improvements (replacing rails with elbows) and reply form repositioning that are evident in the code modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch better-comments-ui-threading-styles-wip

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/comments-ui/src/components/content/replies.tsx`:
- Around line 43-49: The replies map rendering passes props to CommentComponent
but omits the useThreading prop, causing nested replies to default to
non-threaded layout; update the JSX where CommentComponent is instantiated
(inside the visibleReplies iteration rendering reply) to pass
useThreading={useThreading} along with existing props (key={reply.id},
comment={reply}, isLastSibling={idx === visibleReplies.length - 1},
layoutVariant={useThreading ? 'reply' : 'root'}, parent={comment}) so each
rendered CommentComponent receives the same threading flag.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0d4cfccc-a603-447c-a96d-a15eaeca2129

📥 Commits

Reviewing files that changed from the base of the PR and between e1058fb and a5d86c9.

📒 Files selected for processing (8)
  • apps/comments-ui/src/components/content/comment.tsx
  • apps/comments-ui/src/components/content/forms/form.tsx
  • apps/comments-ui/src/components/content/forms/reply-form.tsx
  • apps/comments-ui/src/components/content/replies.tsx
  • apps/comments-ui/src/components/content/reply-tree.tsx
  • apps/comments-ui/src/utils/thread-graph.ts
  • apps/comments-ui/test/unit/components/content/comment.test.jsx
  • apps/comments-ui/test/unit/utils/thread-graph.test.ts

Comment thread apps/comments-ui/src/components/content/replies.tsx
no issue

Permalink scroll targets are preserved for context, but opening a reply form can reload comments and should not re-trigger the initial scroll or highlight.
no issue

Nested replies need the active threading mode so their own reply forms and children keep the threaded layout instead of falling back to flat reply behavior.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/comments-ui/src/components/content/hooks/use-comment-navigation.ts (1)

236-274: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid marking permalink as “already scrolled” before iframe scroll actually runs.

Line 267 sets lastScrolledCommentId before the deferred iframe resize callback fires. If a rerender happens first, effect cleanup cancels that pending callback, and the guard then suppresses retries—so the target may never scroll.

💡 Suggested fix
         const iframe = findContainingIframe(doc);
         if (iframe) {
-            lastScrolledCommentId.current = commentIdToScrollTo;
             return onIframeResize(iframe, () => {
-                scrollToComment(element, commentIdToScrollTo, {preserveScrollTarget: commentIdToScrollTo === commentIdFromHash});
+                const latestElement = containerRef.current?.ownerDocument.getElementById(commentIdToScrollTo);
+                if (!latestElement) {
+                    return;
+                }
+
+                lastScrolledCommentId.current = commentIdToScrollTo;
+                scrollToComment(latestElement, commentIdToScrollTo, {preserveScrollTarget: commentIdToScrollTo === commentIdFromHash});
             });
         }

         lastScrolledCommentId.current = commentIdToScrollTo;
         scrollToComment(element, commentIdToScrollTo, {preserveScrollTarget: commentIdToScrollTo === commentIdFromHash});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/comments-ui/src/components/content/hooks/use-comment-navigation.ts`
around lines 236 - 274, The bug is that lastScrolledCommentId.current is set
before the deferred iframe resize callback runs, which lets a rerender cancel
the pending callback and incorrectly suppress future scrolls; to fix, don’t
assign lastScrolledCommentId.current before calling onIframeResize — instead
move the assignment into the onIframeResize callback (after scrollToComment
runs) so lastScrolledCommentId is only updated when the actual iframe-scroll
completes; update the logic around findContainingIframe, onIframeResize,
scrollToComment and use containerRef/commentIdToScrollTo/commentIdFromHash to
ensure the guard only flips when the scroll has executed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/comments-ui/src/components/content/hooks/use-comment-navigation.ts`:
- Around line 236-274: The bug is that lastScrolledCommentId.current is set
before the deferred iframe resize callback runs, which lets a rerender cancel
the pending callback and incorrectly suppress future scrolls; to fix, don’t
assign lastScrolledCommentId.current before calling onIframeResize — instead
move the assignment into the onIframeResize callback (after scrollToComment
runs) so lastScrolledCommentId is only updated when the actual iframe-scroll
completes; update the logic around findContainingIframe, onIframeResize,
scrollToComment and use containerRef/commentIdToScrollTo/commentIdFromHash to
ensure the guard only flips when the scroll has executed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f1a19751-ea28-4f9c-a431-cd7664098003

📥 Commits

Reviewing files that changed from the base of the PR and between a5d86c9 and b97bc37.

📒 Files selected for processing (3)
  • apps/comments-ui/src/components/content/hooks/use-comment-navigation.ts
  • apps/comments-ui/src/components/content/replies.tsx
  • apps/comments-ui/test/unit/components/content/content.test.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/comments-ui/src/components/content/replies.tsx

no issue

The comments UI changes need a patch package release after merging the latest upstream main changes.
@kevinansfield kevinansfield changed the title Better comments UI threading styles wip Improved comments threading UI May 19, 2026
@kevinansfield kevinansfield merged commit 21d76cf into main May 19, 2026
41 checks passed
@kevinansfield kevinansfield deleted the better-comments-ui-threading-styles-wip branch May 19, 2026 10:31
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