Get started with comments
Install @sanity/collaboration, connect it to the Sanity App SDK, and render a working comments panel on one document.
@sanity/collaboration renders comment threads from data the Sanity SDK gives you. This guide takes you from an empty React app to a working comments panel on one document, with threads, replies, reactions, resolve, and a composer for new comments.
This is a paid feature
This feature is available in the Growth plan.
Prerequisites:
- A Sanity project you can read and write. Comments are scoped to the organization that owns it.
- A React 19.2 app. The components peer on
reactandreact-dom^19.2. - Basic experience with the Sanity App SDK. If you haven't built an App SDK app before, start with the App SDK Quickstart Guide.
- The peer dependencies listed in Requirements:
@sanity/ui^4.0.6,styled-components^6.1,@sanity/icons^5.2.1,@portabletext/editor^8.2.4, and@sanity/sdkand@sanity/sdk-react^3.11.0, installed in Step 1. - A document to comment on. This guide uses
post-123of typepost.
Step 1: Install the package
The package is in beta, on 0.x. A 0.x minor can carry breaking changes, so read the changelog before moving to a new minor.
npm install @sanity/collaborationpnpm add @sanity/collaborationyarn add @sanity/collaborationbun add @sanity/collaborationEvery comment read and write on this page comes from @sanity/sdk-react/collaboration, which ships in @sanity/sdk-react 3.11.0 and later. Install @sanity/sdk-react and @sanity/sdk at that version:
npm install @sanity/sdk-react@^3.11.0 @sanity/sdk@^3.11.0pnpm add @sanity/sdk-react@^3.11.0 @sanity/sdk@^3.11.0yarn add @sanity/sdk-react@^3.11.0 @sanity/sdk@^3.11.0bun add @sanity/sdk-react@^3.11.0 @sanity/sdk@^3.11.0Install @sanity/sdk too: the SDK components import it directly, and as an optional peer it isn't installed automatically.
Sanity UI v4 ships its static styles as a plain stylesheet. Import it once, wherever your app loads global CSS:
import '@sanity/ui/styles.css'Step 2: Configure the SDK
The project and dataset are all SanityApp needs. Comments are scoped to an organization, and the SDK uses the one that owns the project; there's nothing to configure. AuthBoundary handles signing in.
The components render below Sanity UI's ThemeProvider, so App wraps everything in one. If your app already has a ThemeProvider, leave this one out.
import {AuthBoundary, SanityApp} from '@sanity/sdk-react'
import {ThemeProvider} from '@sanity/ui'
import {buildTheme} from '@sanity/ui/theme'
import {Comments} from './Comments'
export function App() {
return (
<ThemeProvider theme={buildTheme()}>
<SanityApp
config={{
projectId: '<your-project-id>',
dataset: 'production',
}}
fallback={<p>Starting…</p>}
>
<AuthBoundary>
<Comments />
</AuthBoundary>
</SanityApp>
</ThemeProvider>
)
}Replace <your-project-id> with your project ID from sanity.io/manage.
Step 3: Render the panel
Two components. SDKCommentsProvider resolves who you are from the SDK and holds the selection, and SDKCommentsPanel is the panel: the document's threads, a status filter, every write a card offers, and an Add a new comment thread button under each field heading.
A field with no threads yet has no heading to hang a composer off, so compose adds a composer at the top of the panel, and its fieldPath names the field that composer writes to. Leave it off and the panel can only add to fields that already have comments.
Both reads suspend on first load, so the Suspense boundaries are yours.
import {SDKCommentsProvider, SDKCommentsPanel} from '@sanity/collaboration/sdk'
import {Suspense} from 'react'
export function Comments() {
return (
<Suspense fallback={<p>Resolving your identity…</p>}>
{/* Keeps the selection in React state. To make pasted links work, see
"Link to a comment". */}
<SDKCommentsProvider>
<Suspense fallback={<p>Loading comments…</p>}>
<SDKCommentsPanel
documentId="post-123"
documentType="post"
compose={{fieldPath: 'title'}}
/>
</Suspense>
</SDKCommentsProvider>
</Suspense>
)
}With no navigation props, SDKCommentsProvider keeps the selection in React state. To make a pasted link open the panel on one comment, hand it your router. See Link to a comment.
Step 4: Check that it worked
Load the page and write a comment in the composer at the top of the panel.
Two things happen:
- The comment appears under a title heading straight away, before the request has settled. Writes apply optimistically.
- Hovering the comment reveals its actions. Resolve, edit, and delete are all there, because the panel wires every write a card offers.
A thread with more than three replies shows the three most recent and collapses the older ones behind a Show N more button. Resolving the parent resolves the thread and moves it out of the Open view; switch the filter at the top of the panel to Resolved to see it again.
Troubleshooting
The app throws Comment components must be rendered inside a <CommentsProvider>. A comment component is mounted outside the provider. Check that SDKCommentsProvider is above every one of them, including anything rendered into a portal or a dialog.
The comments flash unstyled on first paint. @sanity/ui/styles.css is not imported, or is imported after your own global CSS.
Next steps
- To let people mention each other: Enable mentions.
- To make a pasted link open the panel on one comment: Link to a comment.
- To build the panel yourself from
CommentList,CommentThread, andCommentInputwhen its layout stops fitting: Levels of abstraction in the comment stack. - To understand what the SDK hooks behind the panel are doing: Comment data flow.
- The panel from this guide, as an example you can run: get-started.
- The panel written out from its parts, with a copy link and the address in the URL: link-to-a-comment.
Was this page helpful?
Feedback submitted, thanks for helping us improve the docs. Have you tried these alternatives?