# Comments

- Human documentation: [https://docs.univer.ai/guides/sheets/features/comments](https://docs.univer.ai/guides/sheets/features/comments)

- Agent Markdown: [https://docs.univer.ai/guides/sheets/features/comments.md](https://docs.univer.ai/guides/sheets/features/comments.md)

- Requested language: `en-US`

- Content language: `en-US`

- Documentation version: `1.0.0-rc.0`

- Source: [sheets/features/comments.mdx](https://github.com/dream-num/documentation/blob/dev/content/guides/sheets/features/comments.mdx)

---

#### Package metadata

```json
{
  "preset": [
    {
      "client": "@univerjs/preset-sheets-thread-comment",
      "locale": "@univerjs/preset-sheets-thread-comment/locales/en-US",
      "style": "@univerjs/preset-sheets-thread-comment/lib/index.css"
    }
  ],
  "plugins": [
    {
      "client": "@univerjs/thread-comment"
    },
    {
      "client": "@univerjs/thread-comment-ui",
      "locale": "@univerjs/thread-comment-ui/locale/en-US",
      "style": "@univerjs/thread-comment-ui/lib/index.css"
    },
    {
      "client": "@univerjs/sheets-thread-comment",
      "facade": "@univerjs/sheets-thread-comment/facade"
    },
    {
      "client": "@univerjs/sheets-thread-comment-ui",
      "locale": "@univerjs/sheets-thread-comment-ui/locale/en-US",
      "style": "@univerjs/sheets-thread-comment-ui/lib/index.css"
    }
  ],
  "server": "optional"
}
```

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

## Preset Mode

### Installation

#### npm

```bash
npm install @univerjs/preset-sheets-thread-comment
```

#### pnpm

```bash
pnpm add @univerjs/preset-sheets-thread-comment
```

#### yarn

```bash
yarn add @univerjs/preset-sheets-thread-comment
```

#### bun

```bash
bun 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' // [!code ++]
import UniverPresetSheetsThreadCommentEnUS from '@univerjs/preset-sheets-thread-comment/locales/en-US' // [!code ++]
import { createUniver, LocaleType, mergeLocales } from '@univerjs/presets'

import '@univerjs/preset-sheets-core/lib/index.css'
import '@univerjs/preset-sheets-thread-comment/lib/index.css' // [!code ++]

const { univerAPI } = createUniver({
  locale: LocaleType.EN_US,
  locales: {
    [LocaleType.EN_US]: mergeLocales(
      UniverPresetSheetsCoreEnUS,
      UniverPresetSheetsThreadCommentEnUS, // [!code ++]
    ),
  },
  presets: [
    UniverSheetsCorePreset(),
    UniverSheetsThreadCommentPreset(), // [!code ++]
  ],
})
```

## Plugin Mode

### Installation

#### npm

```bash
npm install @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-ui
```

#### pnpm

```bash
pnpm add @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-ui
```

#### yarn

```bash
yarn add @univerjs/thread-comment @univerjs/thread-comment-ui @univerjs/sheets-thread-comment @univerjs/sheets-thread-comment-ui
```

#### bun

```bash
bun 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' // [!code ++]
import { UniverSheetsThreadCommentUIPlugin } from '@univerjs/sheets-thread-comment-ui' // [!code ++]
import SheetsThreadCommentUIEnUS from '@univerjs/sheets-thread-comment-ui/locale/en-US' // [!code ++]
import { UniverThreadCommentPlugin } from '@univerjs/thread-comment' // [!code ++]
import { UniverThreadCommentUIPlugin } from '@univerjs/thread-comment-ui' // [!code ++]
import ThreadCommentUIEnUS from '@univerjs/thread-comment-ui/locale/en-US' // [!code ++]

import '@univerjs/sheets-thread-comment-ui/lib/index.css'
import '@univerjs/thread-comment-ui/lib/index.css' // [!code ++]

import '@univerjs/sheets-thread-comment/facade' // [!code ++]

const univer = new Univer({
  locale: LocaleType.EN_US,
  locales: {
    [LocaleType.EN_US]: mergeLocales(
      ThreadCommentUIEnUS, // [!code ++]
      SheetsThreadCommentUIEnUS, // [!code ++]
    ),
  },
})

univer.registerPlugin(UniverThreadCommentPlugin) // [!code ++]
univer.registerPlugin(UniverThreadCommentUIPlugin) // [!code ++]
univer.registerPlugin(UniverSheetsThreadCommentPlugin) // [!code ++]
univer.registerPlugin(UniverSheetsThreadCommentUIPlugin) // [!code ++]
```

#### Using with Collaboration Feature

If you are using the [Collaboration](https://docs.univer.ai/guides/sheets/features/collaboration.md) feature, configure it as follows:

#### npm

```bash
npm install @univerjs-pro/thread-comment-datasource
```

#### pnpm

```bash
pnpm add @univerjs-pro/thread-comment-datasource
```

#### yarn

```bash
yarn add @univerjs-pro/thread-comment-datasource
```

#### bun

```bash
bun add @univerjs-pro/thread-comment-datasource
```

```typescript
import { UniverThreadCommentDataSourcePlugin } from '@univerjs-pro/thread-comment-datasource' // [!code ++]

univer.registerPlugin(UniverThreadCommentDataSourcePlugin) // [!code ++]
```

## Facade API

Complete Facade API type definitions can be found in the [FacadeAPI](https://docs.univer.ai/reference/facade/thread-comment.md).

### Importing

> [!INFO: 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`](https://docs.univer.ai/reference/facade/thread-comment.md):

| 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     |

```typescript
// Create a new comment
const richText = univerAPI.newRichText().insertText('hello univer')
const commentBuilder = univerAPI.newTheadComment()
  .setContent(richText)

console.log(commentBuilder.content.toPlainText())

// Add the comment to cell A1
const 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`](https://docs.univer.ai/reference/facade/thread-comment.md):

| 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                     |

```typescript
// Get all comments in the workbook
const fWorkbook = univerAPI.getActiveWorkbook()
fWorkbook.getComments()

// Get all comments in the active worksheet
const fWorksheet = fWorkbook.getActiveSheet()
fWorksheet.getComments()

const fRange = fWorksheet.getRange('A1:B2')
// Get the comment of cell A1
fRange.getComment()

// Get all comments in the range A1:B2
fRange.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 workbook
const fWorkbook = univerAPI.getActiveWorkbook()
await fWorkbook.clearComments()

// Clear all comments in the active worksheet
const fWorksheet = fWorkbook.getActiveSheet()
await fWorksheet.clearComments()

const fRange = fWorksheet.getRange('A1:B2')

// Clear the comment of cell A1
await fRange.clearCommentAsync()

// Clear all comments in the range A1:B2
await fRange.clearCommentsAsync()
```

### Get Comment Replies List

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// Get all comments in the worksheet
const 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 A1
const 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 seconds
setTimeout(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 seconds
setTimeout(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](https://docs.univer.ai/reference/facade/events.md).

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.

```ts
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](https://docs.univer.ai/server/collaboration/extensions.md), 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.
