Comments
Comments allow users to add comments and replies within documents, facilitating communication and collaboration among team members.
Preset Mode
Installation
pnpm add @univerjs/preset-sheets-thread-commentnpm install @univerjs/preset-sheets-thread-commentyarn add @univerjs/preset-sheets-thread-commentbun add @univerjs/preset-sheets-thread-commentUsage
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
pnpm add @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-uinpm install @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-uiyarn add @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-uibun add @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-uiUsage
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:
pnpm add @univerjs-pro/thread-comment-datasourcenpm install @univerjs-pro/thread-comment-datasourceyarn add @univerjs-pro/thread-comment-datasourcebun add @univerjs-pro/thread-comment-datasourceimport { 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.
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:
| Method | Description |
|---|---|
| setContent | Set the content of the comment |
| setPersonId | Set the person ID for the comment |
| setDateTime | Set the date and time of the comment |
| setId | Set the ID of the comment |
| setThreadId | Set the thread ID of the comment |
// 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 workbookFfWorksheet.getComments(): Get all comments in the worksheetFRange.getComment(): Get the comment of the top-left cell in the rangeFRange.getComments(): Get all comments in the range
The following are some member methods of FThreadComment:
| Method | Description |
|---|---|
| getIsRoot | Whether the comment is a root comment |
| getCommentData | Get the comment data |
| getReplies | Get the list of replies to the comment |
| getRange | Get the range of the comment |
| getRichText | Get the rich text content of the comment |
| deleteAsync | Delete the comment and its replies |
| updateAsync | Update the content of the comment |
| resolveAsync | Resolve the comment |
| replyAsync | Reply to the comment |
// 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 workbookFWorksheet.clearComments(): Clear all comments in the worksheetFRange.clearCommentAsync(): Clear the comment of the top-left cell in the rangeFRange.clearCommentsAsync(): Clear all comments in the range
// 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
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
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
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
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
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
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
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
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
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
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 instanceworksheet: Current worksheet instancerow: Row index of the commentcol: Column index of the commentcomment: Comment object (onlycommentIdis included in deletion events)
Special parameters:
BeforeCommentUpdateevent includesnewContent: New comment content (RichTextValue type)CommentResolvedandBeforeCommentResolveevents includeresolved: 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.
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?