Comments

Comments allow users to add comments and replies within documents, facilitating communication and collaboration among team members.

Preset Mode

Installation

Shell
pnpm add @univerjs/preset-sheets-thread-comment

Usage

TypeScript
import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core'import UniverPresetSheetsCoreEnUS from '@univerjs/preset-sheets-core/locales/en-US'import { UniverSheetsThreadCommentPreset } from '@univerjs/preset-sheets-thread-comment'import UniverPresetSheetsThreadCommentEnUS from '@univerjs/preset-sheets-thread-comment/locales/en-US'import { createUniver, LocaleType, mergeLocales } from '@univerjs/presets'import '@univerjs/preset-sheets-core/lib/index.css'import '@univerjs/preset-sheets-thread-comment/lib/index.css'const { univerAPI } = createUniver({  locale: LocaleType.EN_US,  locales: {    [LocaleType.EN_US]: mergeLocales(      UniverPresetSheetsCoreEnUS,      UniverPresetSheetsThreadCommentEnUS,     ),  },  presets: [    UniverSheetsCorePreset(),    UniverSheetsThreadCommentPreset(),   ],})

Plugin Mode

Installation

Shell
pnpm add @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-ui

Usage

TypeScript
import { LocaleType, mergeLocales, Univer } from '@univerjs/core'import { UniverSheetsThreadCommentPlugin } from '@univerjs/sheets-thread-comment'import { UniverSheetsThreadCommentUIPlugin } from '@univerjs/sheets-thread-comment-ui'import SheetsThreadCommentUIEnUS from '@univerjs/sheets-thread-comment-ui/locale/en-US'import { UniverThreadCommentPlugin } from '@univerjs/thread-comment'import { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui'import ThreadCommentUIEnUS from '@univerjs/thread-comment-ui/locale/en-US'import '@univerjs/sheets-thread-comment-ui/lib/index.css'import '@univerjs/thread-comment-ui/lib/index.css'import '@univerjs/sheets-thread-comment/facade'const univer = new Univer({  locale: LocaleType.EN_US,  locales: {    [LocaleType.EN_US]: mergeLocales(      ThreadCommentUIEnUS,       SheetsThreadCommentUIEnUS,     ),  },})univer.registerPlugin(UniverThreadCommentPlugin)univer.registerPlugin(UniverThreadCommentUIPlugin)univer.registerPlugin(UniverSheetsThreadCommentPlugin)univer.registerPlugin(UniverSheetsThreadCommentUIPlugin)

Using with Collaboration Feature

If you are using the Collaboration feature, configure it as follows:

Shell
pnpm add @univerjs-pro/thread-comment-datasource
TypeScript
import { UniverThreadCommentDataSourcePlugin } from '@univerjs-pro/thread-comment-datasource'univer.registerPlugin(UniverThreadCommentDataSourcePlugin)

Facade API

Complete Facade API type definitions can be found in the FacadeAPI.

Importing

Plugin mode note

Only plugin mode requires manually importing the Facade package. Preset mode already includes the corresponding Facade package, so no extra import is needed.

TypeScript
import '@univerjs/sheets-thread-comment/facade'

Create Cell Comment

You can create a new comment builder using univerAPI.newTheadComment(), which returns an instance of FTheadCommentBuilder. You can chain methods to set various properties of the comment.

The following are some member methods of FTheadCommentBuilder:

MethodDescription
setContentSet the content of the comment
setPersonIdSet the person ID for the comment
setDateTimeSet the date and time of the comment
setIdSet the ID of the comment
setThreadIdSet the thread ID of the comment
TypeScript
// Create a new commentconst richText = univerAPI.newRichText().insertText('hello univer')const commentBuilder = univerAPI.newTheadComment()  .setContent(richText)console.log(commentBuilder.content.toPlainText())// Add the comment to cell A1const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()const cell = fWorksheet.getRange('A1')const result = await cell.addCommentAsync(commentBuilder)

Get Cell Comments

You can retrieve comments using the following methods, which return an instance of FThreadComment. You can then perform operations such as updating, deleting, or resolving the comment.

  • FWorkbook.getComments(): Get all comments in the workbook
  • FfWorksheet.getComments(): Get all comments in the worksheet
  • FRange.getComment(): Get the comment of the top-left cell in the range
  • FRange.getComments(): Get all comments in the range

The following are some member methods of FThreadComment:

MethodDescription
getIsRootWhether the comment is a root comment
getCommentDataGet the comment data
getRepliesGet the list of replies to the comment
getRangeGet the range of the comment
getRichTextGet the rich text content of the comment
deleteAsyncDelete the comment and its replies
updateAsyncUpdate the content of the comment
resolveAsyncResolve the comment
replyAsyncReply to the comment
TypeScript
// Get all comments in the workbookconst fWorkbook = univerAPI.getActiveWorkbook()fWorkbook.getComments()// Get all comments in the active worksheetconst fWorksheet = fWorkbook.getActiveSheet()fWorksheet.getComments()const fRange = fWorksheet.getRange('A1:B2')// Get the comment of cell A1fRange.getComment()// Get all comments in the range A1:B2fRange.getComments()

Clear Cell Comments

  • FWorkbook.clearComments(): Clear all comments in the workbook
  • FWorksheet.clearComments(): Clear all comments in the worksheet
  • FRange.clearCommentAsync(): Clear the comment of the top-left cell in the range
  • FRange.clearCommentsAsync(): Clear all comments in the range
TypeScript
// Clear all comments in the workbookconst fWorkbook = univerAPI.getActiveWorkbook()await fWorkbook.clearComments()// Clear all comments in the active worksheetconst fWorksheet = fWorkbook.getActiveSheet()await fWorksheet.clearComments()const fRange = fWorksheet.getRange('A1:B2')// Clear the comment of cell A1await fRange.clearCommentAsync()// Clear all comments in the range A1:B2await fRange.clearCommentsAsync()

Get Comment Replies List

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// Get all comments in the worksheetconst comments = fWorksheet.getComments()comments.forEach((comment) => {  // If the comment is a root comment, get its replies  if (comment.getIsRoot()) {    const replies = comment.getReplies()    replies.forEach((reply) => {      console.log(reply.getCommentData())    })  }})

Update/Delete/Resolve/Reply to Comments

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const fWorksheet = fWorkbook.getActiveSheet()// Create a new comment and add it to cell A1const richText = univerAPI.newRichText().insertText('hello univer')const commentBuilder = univerAPI.newTheadComment()  .setContent(richText)  .setId('mock-comment-id')const cell = fWorksheet.getRange('A1')await cell.addCommentAsync(commentBuilder)// Update the comment and reply after 3 secondssetTimeout(async () => {  // Get the comment by ID and update its content  const comment = fWorksheet.getCommentById('mock-comment-id')  const newRichText = univerAPI.newRichText().insertText('Hello Univer AI')  await comment.updateAsync(newRichText)  // Create a new reply comment and set its content  const replyText = univerAPI.newRichText().insertText('Hello Univer AI! GO! GO! GO!')  const reply = univerAPI.newTheadComment().setContent(replyText)  await comment.replyAsync(reply)}, 3000)// Resolve the comment and delete it after 6 secondssetTimeout(async () => {  const comment = fWorksheet.getCommentById('mock-comment-id')  await comment.resolveAsync()  await comment.deleteAsync()}, 6000)

Event Listeners

Complete event type definitions can be found in Events.

The comment module provides a series of events to listen for comment additions, updates, deletions, and resolution status changes. All events can be listened to using univerAPI.addEvent().

Comment Addition Events

univerAPI.Event.CommentAdded: Triggered after a comment is added

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentAdded, (params) => {  const { comment, workbook, worksheet, row, col } = params})// Remove the event listener, use `disposable.dispose()`

univerAPI.Event.BeforeCommentAdd: Triggered before a comment is added

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentAdd, (params) => {  const { comment, workbook, worksheet, row, col } = params  // Cancel the comment addition operation  params.cancel = true})// Remove the event listener, use `disposable.dispose()`

Comment Update Events

univerAPI.Event.CommentUpdated: Triggered after a comment is updated

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentUpdated, (params) => {  const { comment, workbook, worksheet, row, col } = params})// Remove the event listener, use `disposable.dispose()`

univerAPI.Event.BeforeCommentUpdate: Triggered before a comment is updated

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentUpdate, (params) => {  const { comment, workbook, worksheet, row, col, newContent } = params  // Cancel the comment update operation  params.cancel = true})// Remove the event listener, use `disposable.dispose()`

Comment Deletion Events

univerAPI.Event.CommentDeleted: Triggered after a comment is deleted

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentDeleted, (params) => {  const { commentId, workbook, worksheet } = params})// Remove the event listener, use `disposable.dispose()`

univerAPI.Event.BeforeCommentDelete: Triggered before a comment is deleted

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentDelete, (params) => {  const { comment, workbook, worksheet, row, col } = params  // Cancel the comment deletion operation  params.cancel = true})// Remove the event listener, use `disposable.dispose()`

Comment Resolution Status Events

univerAPI.Event.CommentResolved: Triggered after the resolution status of a comment changes

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.CommentResolved, (params) => {  const { comment, row, col, resolved, workbook, worksheet } = params})// Remove the event listener, use `disposable.dispose()`

univerAPI.Event.BeforeCommentResolve: Triggered before the resolution status of a comment changes

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeCommentResolve, (params) => {  const { comment, row, col, resolved, workbook, worksheet } = params  // Cancel the comment resolution operation  params.cancel = true})// Remove the event listener, use `disposable.dispose()`

All events contain the following common parameters:

  • workbook: Current workbook instance
  • worksheet: Current worksheet instance
  • row: Row index of the comment
  • col: Column index of the comment
  • comment: Comment object (only commentId is included in deletion events)

Special parameters:

  • BeforeCommentUpdate event includes newContent: New comment content (RichTextValue type)
  • CommentResolved and BeforeCommentResolve events include resolved: Resolution status of the comment

All Before prefixed event callback functions can return params.cancel = true to prevent the corresponding operation.

Shared comment operations

Import both the shared comment Facade and the product Facade before calling these methods. Product helpers create stable anchors; the shared API handles replies, updates, resolution, and deletion. getComments() reads local state. listCommentsAsync() synchronizes already known threads through the configured data source; it does not discover every thread on the server.

TypeScript
import '@univerjs/thread-comment/facade'const [thread] = univerAPI.getComments({ resolved: false })if (thread) {  await univerAPI.replyCommentAsync({    unitId: thread.unitId,    subUnitId: thread.subUnitId,    threadId: thread.threadId,    content: 'Reviewed.',  })}

Shared discussions

For shared discussions, integrate the Comment Service and Endpoint with Server SDK, then register UniverThreadCommentDataSourcePlugin from @univerjs-pro/thread-comment-datasource after collaboration and license setup. The supplied data source uses /universer-api/comment/unit/{unitId}/... and /universer-api/user/list; expose those routes through your application. Server permissions must cover comment reads and writes independently of document editing.

How is this guide?

© 2026 DreamNum Co., Ltd.