Document-level comments, multi-document panels and DOM styling props
Published: October 29, 2026
This release lets a comment belong to a whole document, groups comments from several documents in one list or panel, and replaces Sanity UI layout props with plain DOM attributes. It also renames the SDK components after their @sanity/collaboration/ui counterparts. Several of these changes break CommentsPanel and styling code written for 0.1.0.
New features
- Document-level comments: a thread can be on a document as a whole, not only on one of its fields, with
fieldPath: ''.compose={{fieldPath: ''}}starts one fromCommentsPanel, whose composer then prompts "Comment on the document…".CommentListheads these threads with the document when it names documents, and otherwise with the newlabels.list.document(default "Document"). The Sanity Studio comments inspector doesn't list document-level comments. Document-level comments need@sanity/sdkand@sanity/sdk-react3.11.0 or later. - Multi-document lists:
CommentListandCommentsPanelgroup comments from several documents. Groups are one field of one document, keyed on the new optionalCommentData.documentId(anddocumentType). Once the threads span more than one document, each heading names the document as well as the field.documentTitle(group)names a group's document,renderFieldHeadingandrenderFieldActionreceive the group'sdocumentId, andscrollToFieldtakes aCommentTargetas well as a field path. - Always-visible actions:
CommentandCommentThreadtakeactions: 'hover' | 'always'.'always'keeps the action row in view instead of revealing it on hover or focus. The default is'hover'. SDKCommentsPaneltakesonCommentCreated(comment), called once a new thread is created, as onSDKPortableTextComments. Use it to close a composer opened withcomposeor to select the new thread.useSDKThreadCallbacksalso accepts a function from a thread to its document's handle.
Improvements
- In development,
CommentsPanelwarns when the threads span several documents andcomposehas nodocumentId. panel.composerPlaceholderreceives the full target, so you can name the document as well as the field.- Multi-document headings truncate the document title before the field, and show the full heading in a tooltip when needed.
- The inline comment button opens from the bottom-right corner of the selection and runs right, or left when it doesn't fit, instead of centered under the selection. The
placementprop onInlineCommentInputstill overrides it.
Breaking changes
- SDK component names:
DocumentCommentsPanelis nowSDKCommentsPanel(withSDKCommentsPanelPropsandSDKCommentsPanelAction), andInlineCommentsPluginis nowSDKPortableTextComments(withSDKPortableTextCommentsProps). Props and behavior are unchanged, so update the imports. - Styling props:
Comment,CommentThread,CommentListandCommentBadgeno longer accept Sanity UI props (padding,radius,tone,border,shadow,gap,mode,fontSizeand others). Each takes the DOM attributes of the element it renders:className,style,id,aria-*and event handlers. Style them through the Sanity UI theme, and useclassNameorstylefor placement. Thedata-*attributes in the rendered DOM aren't a styling API and can change in any release. See Theme the components. onThreadCreate(fieldPath, message)is nowonThreadCreate(target, message), andlabels.composerPlaceholder(fieldPath)is nowcomposerPlaceholder(target).targetis the newCommentTarget,{fieldPath, documentId?}, exported from the root entry.draftKeyis removed. Drafts are always kept per target, so they survive a composer unmounting and carry between panels over the same document. The new optionaldraftScopestring prefixes their keys, to keep two panels over one document apart.- The
fieldPathprop onCommentsPanelis replaced bycompose: {fieldPath, documentId?, onDiscard?}.documentIdsays which document the composer writes to, andonDiscardmakes it a composer opened on request: it takes focus when it mounts, and Cancel or Escape callsonDiscard.SDKCommentsPaneltakescomposewithoutdocumentId, since its document is the handle's. renderFieldHeading(group)is nowrenderFieldHeading(group, {heading})on bothCommentListandCommentsPanel, whereheadingis the built-in heading. Both components now read the result the same way:nullrenders no heading andundefinedrenders the built-in one.- The composer above the list remounts when its target changes, so unsent text stays with the field and document it was written for.
Related documentation
Theme the comment components
Change how the comment components look through the Sanity UI theme, a few typed props, and composition.
Comment components
What each comment component is responsible for, how they nest, and what changes when you compose the primitives yourself.
SDK-wired comment components
What each export of @sanity/collaboration/sdk replaces, and when to use it or drop down to the SDK hooks.