constellation threaded

<atproto-comments>

Threaded replies via Constellation backlinks. Each reply fetched from its author's PDS — true federated threading, no AppView.

<atproto-comments src="at://..." depth="1" show-count></atproto-comments>
NameTypeDefaultDescription
src * string Post AT-URI to fetch replies for.
depth number 1 Recursion depth. depth=0 shows a 'Show replies' button per row instead of auto-recursing.
limit number 10 Replies per page.
show-count boolean Render the 'N replies' header above the thread.
constellation string Override the Constellation endpoint.

External CSS can target these via atproto-comments::part(<name>) { ... }.

PartWhat it is
head'N replies' counter (only with show-count).
threadContainer with role=list.
replyEach reply row (compact post + optional nested comments or expand button).
expand'Show replies' button shown when depth=0.
loadmore / emptyPagination button and empty-state.

Constellation indexes every ATProto record's links across the entire firehose. A reply record has reply.parent.uri pointing at whatever it's replying to. So the question "what replies does post X have?" becomes: "what records link to X via app.bsky.feed.post:reply.parent.uri?" That's a single Constellation getBacklinks call.

Each reply returned is {did, collection, rkey}. The component constructs the AT-URI and instantiates a compact <atproto-post> pointing at it — which in turn fetches from the REPLY author's PDS, not ours. Replies from a self-hosted PDS render the same way as replies from bsky.social. True federation.

At depth=1, limit=10 (defaults), the worst case is ~11 Constellation backlink-list calls + ~10 PDS getRecord calls + ~10 DID doc resolutions. Bumping depth=2 multiplies by 10 — be deliberate.

With depth=0, each reply row shows an "Expand replies" button that lazy-instantiates a nested <atproto-comments depth="0"> on click. Use this mode when you don't know in advance how deep the thread goes — cheapest initial render.

The canonical use case: you post a Bluesky thread about your latest blog post, then embed the comments on the blog post itself. Each visitor sees the live conversation without leaving your site.

<article>
  <h1>My latest post</h1>
  <p>... content ...</p>
</article>

<section>
  <h2>Discussion</h2>
  <p>This conversation happens on
    <a href="https://bsky.app/profile/you/post/...">Bluesky</a>.</p>
  <atproto-comments src="at://..." depth="1" show-count></atproto-comments>
</section>
  • <atproto-comments> — replies below an already-visible post (blog comments pattern). Cheapest.
  • <atproto-thread> — ancestors + focal + replies. When the focal post is mid-thread and the parent chain matters.