Skip to main content
useSuperDocComments() gives you the live comments feed. ui.selection.capture() freezes the selection so a composer textarea can take focus without losing the anchor. ui.comments.createFromCapture(capture, { text }) posts the comment.

A minimal comments list

items is the array sourced from editor.doc.comments.list(). Each item is a DiscoveryItem<CommentDomain> with id, text, creatorName, creatorEmail, createdTime, parentCommentId, status, target, anchoredText.

Disable the built-in comments UI

When you’re rendering your own panel, turn off SuperDoc’s so the two don’t overlap.
Imported comments still flow through the engine on export and import. The flag turns off the rendered UI, not the data.

Add a comment from a selection

Two paths. Pick based on whether your composer takes focus from the editor.

When the user clicks “Comment” with the selection still active

createFromSelection reads the live editor selection. If your button doesn’t steal focus, the selection is still there when the click handler runs.

When you open a composer with a textarea

A textarea takes focus. The editor selection clears. By the time the user presses “Post”, the live selection is gone. Capture it first.
captured.target is the same shape editor.doc.comments.create({ target }) accepts. quotedText gives you the anchored text for previewing in the composer. See the selection capture example for a runnable vanilla version: open a composer, move focus to a textarea, and post against the original selection.

Resolve and reopen

All three return a Document API receipt. The next snapshot from useSuperDocComments() reflects the change.

Scroll to a comment

Scrolls the editor viewport to the comment’s anchor. Body-scoped today: the comment-address contract carries no story field, so a comment anchored in a header, footer, or note doesn’t navigate through this call. For now, scroll those manually via ui.viewport.scrollIntoView({ target: ... }) once you’ve resolved the right address yourself.

Threads and replies

Comments form threads via parentCommentId. Each item from useSuperDocComments() carries one if it’s a reply; group your sidebar by parentCommentId to render thread roots with their replies stacked underneath.
To post a reply, call ui.comments.reply(parentCommentId, { text }). The reply inherits the parent’s anchor, so you don’t pass a target. Empty or whitespace-only text returns a NO_OP receipt instead of hitting the API.
The next snapshot from useSuperDocComments() includes the reply, threaded under the parent via parentCommentId. The reference demo’s ActivitySidebar ships this pattern with focus management and Ctrl/Cmd+Enter to post.

Theming

Comment cards, body text, timestamps, and active states are themable via --sd-ui-comments-* CSS variables. See Theming overview and Custom themes for the full token list.

Trade-offs

  • useSuperDocComments returns a memoized snapshot. Re-renders happen only when items, total, or activeIds change.
  • createFromSelection returns { success: false, failure: { code: 'NO_OP' } } when there’s no selection target. Guard with selection.empty or selection.target == null.
  • createFromCapture stays valid as long as the captured snapshot’s blocks still exist. If the user deleted the anchored text between capture and post, the post fails with INVALID_TARGET.
  • Multi-paragraph anchors export as one commentRangeStart / commentRangeEnd pair per comment id, conformant with ECMA-376 §17.13.4.