Review Thread

A review conversation anchored to a line of code, with the line shown as context. Resolving is always a callback — a resolved thread is server truth other reviewers see.

src/components/ui/review-thread.tsx

About

From the component's own source, where it was written.

A review conversation anchored to a line of code.

The anchor is rendered as context above the comments — a thread detached from the line it is about is unreadable, and re-finding that line is the main cost of reviewing in a browser.

Resolving is a callback, never local state. A resolved thread is server truth that other reviewers see; a component that hid it locally would show two people different threads on the same diff.

Install

npx astralyx-ui add review-thread

Usage

import { ReviewThread } from '@/components/ui/review-thread'

<ReviewThread
  path="src/lib/styles.ts"
  line={68}
  snippet="  xs: 'h-7 gap-1.5 px-3.5 text-xs',"
  comments={comments}
  onReply={reply}
  onResolve={resolve}
/>

Composer

Change the props and the source below follows.

src/lib/styles.ts:68
  xs: 'h-7 gap-1.5 px-3.5 text-xs',
  • Grace Hopper
    Grace Hopper2h ago
    Should this opt out of the squircle so it reads as a true pill?
  • Ada Lovelace
    Ada Lovelace1h agoPending
    Yes — a squircle at 50% looks like a rounded rectangle at this size.
Props
tsx
<ReviewThread
  path="src/lib/styles.ts"
  line={68}
  comments={comments}
  resolved={false}
  onResolve={resolve}
/>

Examples

Thread

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

ReviewThread

Extends Omit<ComponentProps<'div'>, 'onSubmit'>.

PropTypeDefaultDescription
pathstring—The anchor. A thread detached from its line is unreadable, and re-finding that line is the main cost of reviewing in a browser.
linenumber—The anchor. A thread detached from its line is unreadable, and re-finding that line is the main cost of reviewing in a browser.
snippetstring—The anchor. A thread detached from its line is unreadable, and re-finding that line is the main cost of reviewing in a browser.
commentsReviewComment[]required{ id, author, body, time?, pending? }.
resolvedbooleanfalseResolution is never local state — it is shared truth, so the component only reports the intent.
onResolve() => void—Resolution is never local state — it is shared truth, so the component only reports the intent.
onReply(body: string) => void—Adds the reply box. Omit it for a read-only thread.
resolvedLabelReactNode'Resolved'—
pendingLabelReactNode'Pending'Badge on a comment awaiting a reply.
replyLabelReactNode'Reply'—
replyPlaceholderstring'Reply…'—
replyFieldLabelstring'Reply to thread'Accessible name for the reply field.
resolveLabelReactNode'Resolve'—

Types

ReviewComment

A review conversation anchored to a line of code.

FieldTypeDescription
idstring—
authorstring—
bodyReactNode—
time?ReactNode—
pending?booleanMarks the review that requested changes.