constellation threaded
<atproto-comments>
Threaded replies via Constellation backlinks. Each reply fetched from its author's PDS — true federated threading, no AppView.
Live
<atproto-comments src="at://..." depth="1" show-count></atproto-comments> Attributes
| Name | Type | Default | Description |
|---|---|---|---|
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. |
Parts
External CSS can target these via atproto-comments::part(<name>) { ... }.
| Part | What it is |
|---|---|
head | 'N replies' counter (only with show-count). |
thread | Container with role=list. |
reply | Each reply row (compact post + optional nested comments or expand button). |
expand | 'Show replies' button shown when depth=0. |
loadmore / empty | Pagination button and empty-state. |
How threading works without an AppView
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.
Fan-out budget
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.
Blog comments pattern
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> When to use this vs alternatives
<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.