Comment thread
Threaded comments with replies, reactions, mentions, inline edit, and resolve.
pnpm dlx shadcn@latest add @uiarc/comment-threadLive · keyboard ready
- Review threads on documents, designs, tickets, or pull requests.
- Discussions that need replies, reactions, mentions, and a resolved state.
- Sidebars of feedback attached to one object.
- Use chat-thread for real-time back-and-forth conversation.
- Use ai-chat for assistant conversations with streaming replies.
- Use mention-input alone when you only need a composer.
Installation
Add Comment thread with the shadcn CLI, or copy the source by hand.
pnpm dlx shadcn@latest add @uiarc/comment-threadAdds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:
example.tsx
import { CommentThread, type ThreadComment } from "@/registry/components/comment-thread/comment-thread"; export function HeadlineDiscussion({ initial, me }: { initial: ThreadComment[]; me: { id: string; name: string; avatar?: string } }) { return ( <CommentThread title="Hero headline" currentUser={me} defaultComments={initial} onCommentsChange={(_, event) => syncComment(event)} onResolvedChange={resolved => setThreadResolved("hero", resolved)} /> );}API reference
2 parts. The first is the root.
CommentThread
A threaded discussion: nested replies that collapse, reactions with rolling counts, in-place edit and delete, @mention autocomplete, and resolving that folds the thread into a chip.
PropTypeDefaultDescription
commentsThreadComment[]–The comment tree (controlled).defaultCommentsThreadComment[][]Initial tree when uncontrolled.onCommentsChange(comments: ThreadComment[], event: CommentThreadEvent) => void–Called with the full next tree and what changed: reply, edit, delete, or react.currentUserRequiredCommentAuthor–The person writing. Their comments can be edited and deleted.peopleCommentAuthor[]–People who can be mentioned. Defaults to everyone in the thread.resolvedboolean–Resolved state (controlled).defaultResolvedbooleanfalseInitial resolved state.onResolvedChange(resolved: boolean) => void–Called on Resolve and Reopen.titleReactNode–What the thread is about, shown in the header, such as "Hero headline".reactionsstring[]["👍", "❤️", "🎉", "👀", "🚀", "✅"]Emoji offered by the reaction picker.placeholderstring–Composer placeholder.maxDepthnumber2Replies deeper than this attach to the deepest allowed parent.nowLabelstring–createdAt label for comments written now.classNamestring–Extra class on the section.refRef<HTMLElement>–The section element.ThreadComment
One comment in the tree.
PropTypeDefaultDescription
idRequiredstring–Stable id.authorRequired{ id: string; name: string; avatar?: string }–Author. Initials show without an avatar.bodyRequiredstring–Plain text. "@Full Name" mentions of known people are highlighted.createdAtRequiredstring–Display label such as "2h" or "Sep 18".editedboolean–Shows an edited mark.deletedboolean–A deleted comment with replies stays as a quiet placeholder.reactions{ emoji: string; users: string[] }[]–Reactions and who gave them.repliesThreadComment[]–Nested replies.- ⌘+EnterorCtrl+Enter
- Sends the composer.
- @
- Opens mention suggestions in the composer.
- ArrowUporArrowDown
- Move through mention suggestions.
- EnterorTab
- Insert the active mention.
- Escape
- Closes suggestions, then cancels an edit or reply; also closes the reaction picker or delete confirmation.
- The composer is a combobox with a listbox of people and aria-activedescendant.
- Each comment is an article labelled with author and time; deleted ones read "Deleted comment".
- Reaction chips are toggle buttons with aria-pressed and a label like "👍 3, including you".
- Reply toggles expose aria-expanded; icon-only actions have specific labels.
- The thread height springs when replies expand, comments arrive, or the thread folds into the resolved chip.
- Reaction counts roll to the new value; chips move with layout animation as they are added or removed.
- Edit, confirm, and picker rows slide in from the side.
- Reduced motion swaps content without travel and turns off transitions.
- Below 420px the composer hides its avatar and nested replies indent less (12px).
- Hover styles only apply on fine pointers; every action is a visible button on touch.
- Each change rebuilds the tree immutably and renders every comment; paginate or collapse very long threads.
- Reply nesting is capped by maxDepth, which keeps indentation and render depth bounded.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Choose it for comments attached to a document, design, or record. Persist changes with the event passed to onCommentsChange rather than diffing trees.
- currentUser decides which comments show Edit and Delete; enforce the same rule on your server.
- Deleting a comment with replies keeps a placeholder so the thread structure survives.
The full library index for assistants is at /llms.txt.
Hero headline
4 commentsCan we try a shorter headline here? @Emma Collins had a version that fit on one line at 390 px.
Yes, “Plan less. Ship more.” Dropping it into the file now.
Works for me. It also saves the second line on mobile.
Once this lands I'll update the social image copy to match. @Chloe Nguyen can you check the click through numbers after?
Signed in as Emma Collins