> ## Documentation Index
> Fetch the complete documentation index at: https://velt.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Customize Behavior

> Configure Velt Comments behavior: threads, mentions, attachments, recordings, visibility, autocomplete, and other runtime options for the comment composer.

# Threads

#### addCommentAnnotation

* Adds a new comment annotation.
* Params: [AddCommentAnnotationRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addcommentannotationrequest)
* Returns: [AddCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addcommentannotationevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentAnnotation = {
>   comments: [
>     {
>       commentText: 'This is a comment',
>       commentHtml: '<p>This is a comment</p>',
>     }
>   ]
> };
> const addCommentAnnotationRequest = {
>   annotation: commentAnnotation
> };
>
> // Hook
> const { addCommentAnnotation } = useAddCommentAnnotation();
> const addCommentAnnotationEventData = await addCommentAnnotation(addCommentAnnotationRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const addCommentAnnotationEventData = await commentElement.addCommentAnnotation(addCommentAnnotationRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentAnnotation = {
>   comments: [
>     {
>       commentText: 'This is a comment',
>       commentHtml: '<p>This is a comment</p>',
>     }
>   ]
> };
> const addCommentAnnotationRequest = {
>   annotation: commentAnnotation
> };
>
> const commentElement = Velt.getCommentElement();
> const addCommentAnnotationEventData = await commentElement.addCommentAnnotation(addCommentAnnotationRequest);
> ```

#### addCommentOnSelectedText

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/images/addCommentOnSelectedText.png?fit=max\&auto=format\&n=gAz_vLsG-ukKamYM\&q=85\&s=b7a0b8619a4ec193ebf6ae6513d1c86e)

By default, when you highlight over any text in `textMode` a Comment Tool button will appear. Clicking the button will add a comment on the highlighted text.

If you want to trigger the comment using an API method call instead of clicking the button, you can do the following:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> // to add comment on selected text
> commentElement.addCommentOnSelectedText();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> // to add comment on selected text
> commentElement.addCommentOnSelectedText();
> ```

> [!NOTE]
>
> Default text comments and pin comments are disabled on TipTap and other ProseMirror-based editors. Use the dedicated [Tiptap](https://velt.dev/docs/async-collaboration/comments/setup/tiptap.md) or [ProseMirror](https://velt.dev/docs/async-collaboration/comments/setup/prosemirror.md) Velt comment plugin for those editors instead.

#### addCommentOnElement

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/images/addCommentOnElement.png?fit=max\&auto=format\&n=gAz_vLsG-ukKamYM\&q=85\&s=b5b718a6fd3a45ef546d79065a95c302)

Adds a Comment on a specific element by ID.

To add a comment on a specific element through an API method, use the `addCommentOnElement()` method and pass in an object with the schema shown in the example:

**Example 1: Add comment with targetElementId only:**

> [tab] React / Next.js
>
> ```jsx theme={null}
> const element = {
>   targetElement: {
>     elementId: "element_id", // optional (pass elementId if you want to add comment on a specific element)
>     targetText: "target_text", // optional (pass targetText if you want to add comment on a specific text)
>     occurrence: 1, // optional (default: 1) This is relevant for text comment. By default, we will attach comment to the first occurrence of the target text in your document. You can change this to attach your comment on a more specific text.
>     selectAllContent: true, // Set to `true` if you want to select all the text content of the target element.
>   },
>   commentData: [
>     {
>       commentText: "This is awesome! Well done.", // To set plain text content
>       commentHtml:
>         'This <span style="color: green; background-color: aliceblue; display: inline-block; padding: 4px; border-radius: 4px;">is test</span> comment.', // To set HTML formatted content
>       replaceContentText: "This is new comment", // provide this replaceContentText to replace current text with
>       replaceContentHtml: "<span>This is <b>new</b> comment.</span>", // If replacement text contains html formatted text, then provide it here
>     },
>   ],
>   status: "open", // optional (default: open)
> };
>
> const commentElement = client.getCommentElement();
> commentElement.addCommentOnElement(element);
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const element = {
>   targetElement: {
>     elementId: "element_id", // optional (pass elementId if you want to add comment on a specific element)
>     targetText: "target_text", // optional (pass targetText if you want to add comment on a specific text)
>     occurrence: 1, // optional (default: 1) This is relevant for text comment. By default, we will attach comment to the first occurrence of the target text in your document. You can change this to attach your comment on a more specific text.
>     selectAllContent: true, // Set to `true` if you want to select all the text content of the target element.
>   },
>   commentData: [
>     {
>       commentText: "This is awesome! Well done.", // To set plain text content
>       commentHtml:
>         'This <span style="color: green; background-color: aliceblue; display: inline-block; padding: 4px; border-radius: 4px;">is test</span> comment.', // To set HTML formatted content
>       replaceContentText: "This is new comment", // provide this replaceContentText to replace current text with
>       replaceContentHtml: "<span>This is <b>new</b> comment.</span>", // If replacement text contains html formatted text, then provide it here
>     },
>   ],
>   status: "open", // optional (default: open)
> };
>
> const commentElement = Velt.getCommentElement();
> commentElement.addCommentOnElement(element);
> ```

#### addManualComment

* This feature is particularly useful for complex UIs where you need precise control over the placement of Comment Pins.
* Using this you can manually set the position of Comment Annotations.
* Handle click events on your canvas/document and use this method to create a comment with custom metadata.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const context = {
>   position: {x: 200, y: 100},
> };
> const commentElement = client.getCommentElement();
> const config: ManualCommentAnnotationConfig = {
> 	context: context, // your context here
> };
> commentElement.addManualComment(config);
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const context = {
>   position: {x: 200, y: 100},
> };
> const commentElement = Velt.getCommentElement();
> const config: ManualCommentAnnotationConfig = {
> 	context: context, // your context here
> };
> commentElement.addManualComment(config);
> ```

#### Document-Level Comments

* Show one comment on every location of its document, such as a site-wide footer.
* Set `isDocumentLevel: true` when you create the comment. Location filters and `excludeLocationIds` do not hide it.
* Set `targetElementId` to the footer. The pin draws on every page where that element is visible.
* Params: `isDocumentLevel` on the `annotation` passed to `addCommentAnnotation`, or on the config passed to `addManualComment`.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Hook
> const { addCommentAnnotation } = useAddCommentAnnotation();
> await addCommentAnnotation({
>   annotation: {
>     isDocumentLevel: true,
>     targetElementId: 'site-footer',
>     comments: [{ commentText: 'The privacy link is broken.' }],
>   },
> });
>
> // API Method
> const commentElement = client.getCommentElement();
> await commentElement.addCommentAnnotation({
>   annotation: {
>     isDocumentLevel: true,
>     targetElementId: 'site-footer',
>     comments: [{ commentText: 'The privacy link is broken.' }],
>   },
> });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> await commentElement.addCommentAnnotation({
>   annotation: {
>     isDocumentLevel: true,
>     targetElementId: 'site-footer',
>     comments: [{ commentText: 'The privacy link is broken.' }],
>   },
> });
> ```

> [!NOTE]
>
> Database queries such as `getCommentAnnotations({ locationIds })` still match the stored location. Text comments are never document-level.

#### Comment and Reply Placeholders

Customize the placeholder text shown in the Comments dialog inputs to match your product voice and guide first-time users.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using props on VeltComments
> <VeltComments commentPlaceholder="Text Comment" replyPlaceholder="Text Reply" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments comment-placeholder="test comment placeholder" reply-placeholder="test reply placeholder"></velt-comments>
> ```

To customize placeholder text shown when **editing** an existing comment or reply, use `editPlaceholder`, `editCommentPlaceholder`, and `editReplyPlaceholder`. See [`VeltCommentsProps`](https://velt.dev/docs/api-reference/sdk/models/data-models#veltcommentsprops) for details.

#### deleteCommentAnnotation

* Deletes a comment annotation
* Params: [DeleteCommentAnnotationRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deletecommentannotationrequest)
* Returns: [DeleteCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deletecommentannotationevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const deleteCommentAnnotationRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> // Hook
> const { deleteCommentAnnotation } = useDeleteCommentAnnotation();
> const deleteCommentAnnotationEvent = await deleteCommentAnnotation(deleteCommentAnnotationRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const deleteCommentAnnotationEvent = await commentElement.deleteCommentAnnotation(deleteCommentAnnotationRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const deleteCommentAnnotationRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> const commentElement = Velt.getCommentElement();
> const deleteCommentAnnotationEvent = await commentElement.deleteCommentAnnotation(deleteCommentAnnotationRequest);
> ```

#### deleteSelectedComment

To delete a comment using an API method, use the `deleteSelectedComment()` method.

> [tab] React / Next.js
>
> ```jsx theme={null}
> if (client) {
>   const commentElement = client.getCommentElement();
>   commentElement.deleteSelectedComment();
> }
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> if (Velt) {
>   const commentElement = Velt.getCommentElement();
>   commentElement.deleteSelectedComment();
> }
> ```

### [getCommentAnnotationsCount](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#getcommentannotationscount)

* Get the total and unread comment annotations count of all the comment annotations across specified Organization, Folder, Document and Multiple Documents levels.
* If you don't specify any query, it will return data from the folder/documents specified in the `setDocuments` method.
* You can also use this API without setting the document.
* **Auto-batching:** When 2+ `documentIds` are provided, requests are automatically batched to reduce persistence listeners. Use `debounceMs` to control batching delay (default: 5000ms).
* **Params:** (optional) [CommentRequestQuery](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentrequestquery)
  * Set `aggregateDocuments` to `true` to aggregate comment counts across all documents set in the `setDocuments` method, returning a single combined count instead of per-document counts.
  * Set `batchedPerDocument` to `true` if you want to display comment count for a large number of documents (e.g., 100 documents) on the same page. This is now automatically enabled when 2+ `documentIds` are provided.
  * Refer to [CommentRequestQuery](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentrequestquery) for more parameters you can use.
* **Returns:** [GetCommentAnnotationsCountResponse](https://velt.dev/docs/api-reference/sdk/models/data-models.md#getcommentannotationscountresponse)

> [tab] React / Next.js
>
> ```jsx Organization Level theme={null}
> const { data } = useCommentAnnotationsCount({ organizationId: 'org1' });
>
> useEffect(() => {
> if (data) {
> console.log('Comment annotations count for org1:', data);
> }
> }, [data]);
>
> ```
>
> ```jsx Folder Level theme={null}
> const { data } = useCommentAnnotationsCount({
>   organizationId: 'org1',
>   folderId: 'folder2',
>   allDocuments: true
> });
>
> useEffect(() => {
>   if (data) {
>     console.log('Comment annotations count for folder2:', data);
>   }
> }, [data]);
> ```
>
> ```jsx Document Level (Default) theme={null}
> const { data } = useCommentAnnotationsCount();
>
> useEffect(() => {
>   if (data) {
>     console.log("Comment annotations count:", data);
>   }
> }, [data]);
> ```
>
> ```jsx Multiple Documents (auto-batched) theme={null}
> const { data } = useCommentAnnotationsCount({
>   documentIds: ["doc1", "doc2", "doc3"],
> });
>
> useEffect(() => {
>   if (data) {
>     // Auto-batching reduces listeners from 3 to 1 for this example
>     console.log("Comment annotations count for multiple documents:", data);
>   }
> }, [data]);
> ```
>
> ```jsx Aggregate Documents theme={null}
> const { data } = useCommentAnnotationsCount({ aggregateDocuments: true });
>
> useEffect(() => {
>   if (data) {
>     console.log("Aggregated comment annotations count:", data);
>   }
> }, [data]);
> ```
>
> ```jsx Aggregate Multiple Documents (auto-batched) theme={null}
> const { data } = useCommentAnnotationsCount({
>   documentIds: ["doc1", "doc2", "doc3"],
>   aggregateDocuments: true,
> });
>
> useEffect(() => {
>   if (data) {
>     // Auto-batching reduces listeners from 3 to 1 for this example
>     console.log(
>       "Aggregated comment annotations count for multiple documents:",
>       data,
>     );
>   }
> }, [data]);
> ```
>
> ```jsx Filter out Ghost Comments theme={null}
> const { data } = useCommentAnnotationsCount({ filterGhostComments: true });
>
> useEffect(() => {
>   if (data) {
>     console.log("Filtered comment annotations count:", data);
>   }
> }, [data]);
> ```
>
> ```jsx Custom Debounce for Auto-batching theme={null}
> const { data } = useCommentAnnotationsCount({
>   documentIds: ["doc1", "doc2", "doc3"],
>   debounceMs: 3000, // customize debounce (default is 5000ms)
> });
>
> useEffect(() => {
>   if (data) {
>     // Auto-batching reduces listeners from 3 to 1 for this example
>     // Custom debounce triggers updates faster (3s instead of default 5s)
>     console.log("Comment annotations count with custom debounce:", data);
>   }
> }, [data]);
> ```
>
> **Using API:**
>
> ```jsx Organization Level theme={null}
> const commentElement = client.getCommentElement();
> commentElement.getCommentAnnotationsCount({ organizationId: 'org1' }).subscribe((response) => {
>   console.log('getCommentAnnotationsCount with organizationId', response.data);
> });
> ```
>
> ```jsx Folder Level theme={null}
> const commentElement = client.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({
>     organizationId: "org1",
>     folderId: "folder2",
>     allDocuments: true,
>   })
>   .subscribe((response) => {
>     console.log(
>       "getCommentAnnotationsCount with organizationId and folderId and allDocuments",
>       response.data,
>     );
>   });
> ```
>
> ```jsx Document Level (Default) theme={null}
> const commentElement = client.getCommentElement();
> commentElement.getCommentAnnotationsCount().subscribe((response) => {
>   console.log("getCommentAnnotationsCount", response.data);
> });
> ```
>
> ```jsx Multiple Documents (auto-batched) theme={null}
> const commentElement = client.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({
>     documentIds: ["doc1", "doc2", "doc3"],
>   })
>   .subscribe((response) => {
>     // Auto-batching reduces listeners from 3 to 1 for this example
>     console.log(
>       "getCommentAnnotationsCount for multiple documents",
>       response.data,
>     );
>   });
> ```
>
> ```jsx Aggregate Documents theme={null}
> const commentElement = client.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({ aggregateDocuments: true })
>   .subscribe((response) => {
>     console.log(
>       "getCommentAnnotationsCount with aggregateDocuments",
>       response.data,
>     );
>   });
> ```
>
> ```jsx Aggregate Multiple Documents (auto-batched) theme={null}
> const commentElement = client.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({
>     documentIds: ["doc1", "doc2", "doc3"],
>     aggregateDocuments: true,
>   })
>   .subscribe((response) => {
>     // Auto-batching reduces listeners from 3 to 1 for this example
>     console.log(
>       "getCommentAnnotationsCount for aggregated multiple documents",
>       response.data,
>     );
>   });
> ```
>
> ```jsx Filter out Ghost Comments theme={null}
> const commentElement = client.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({ filterGhostComments: true })
>   .subscribe((response) => {
>     console.log(
>       "getCommentAnnotationsCount with filterGhostComments",
>       response.data,
>     );
>   });
> ```
>
> ```jsx Custom Debounce for Auto-batching theme={null}
> const commentElement = client.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({
>     documentIds: ["doc1", "doc2", "doc3"],
>     debounceMs: 3000, // customize debounce (default is 5000ms)
>   })
>   .subscribe((response) => {
>     // Auto-batching reduces listeners from 3 to 1 for this example
>     // Custom debounce triggers updates faster (3s instead of default 5s)
>     console.log(
>       "Comment annotations count with custom debounce:",
>       response.data,
>     );
>   });
> ```

> [tab] Other Frameworks
>
> ```js Organization Level theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.getCommentAnnotationsCount({ organizationId: 'org1' }).subscribe((response) => {
>   console.log('getCommentAnnotationsCount with organizationId', response.data);
> });
> ```
>
> ```js Folder Level theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({
>     organizationId: "org1",
>     folderId: "folder2",
>     allDocuments: true,
>   })
>   .subscribe((response) => {
>     console.log(
>       "getCommentAnnotationsCount with organizationId and folderId and allDocuments",
>       response.data,
>     );
>   });
> ```
>
> ```js Document Level (Default) theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.getCommentAnnotationsCount().subscribe((response) => {
>   console.log("getCommentAnnotationsCount", response.data);
> });
> ```
>
> ```js Multiple Documents (auto-batched) theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({
>     documentIds: ["doc1", "doc2", "doc3"],
>   })
>   .subscribe((response) => {
>     // Auto-batching reduces listeners from 3 to 1 for this example
>     console.log(
>       "getCommentAnnotationsCount for multiple documents",
>       response.data,
>     );
>   });
> ```
>
> ```js Aggregate Documents theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({ aggregateDocuments: true })
>   .subscribe((response) => {
>     console.log(
>       "getCommentAnnotationsCount with aggregateDocuments",
>       response.data,
>     );
>   });
> ```
>
> ```js Filter Ghost Comments theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({ filterGhostComments: true })
>   .subscribe((response) => {
>     console.log(
>       "getCommentAnnotationsCount with filterGhostComments",
>       response.data,
>     );
>   });
> ```
>
> ```js Custom Debounce for Auto-batching theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement
>   .getCommentAnnotationsCount({
>     documentIds: ["doc1", "doc2", "doc3"],
>     debounceMs: 3000, // customize debounce (default is 5000ms)
>   })
>   .subscribe((response) => {
>     // Auto-batching reduces listeners from 3 to 1 for this example
>     // Custom debounce triggers updates faster (3s instead of default 5s)
>     console.log(
>       "Comment annotations count with custom debounce:",
>       response.data,
>     );
>   });
> ```

#### getUnreadCommentAnnotationCountByLocationId

* Get the number of `CommentAnnotations` with at least 1 unread Comment by Location Id.

> [tab] React / Next.js
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const count = useUnreadCommentAnnotationCountByLocationId(locationId);
> useEffect(() => {
>   console.log(count, "countObj");
> }, [count]);
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> if (client) {
>   const commentElement = client.getCommentElement();
>   let subscription = commentElement
>     .getUnreadCommentAnnotationCountByLocationId(locationId)
>     .subscribe((countObj) => {
>       console.log(countObj);
>     });
> }
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> if (Velt) {
>   const commentElement = Velt.getCommentElement();
>   let subscription = commentElement
>     .getUnreadCommentAnnotationCountByLocationId(locationId)
>     .subscribe((countObj) => {
>       console.log(countObj);
>     });
> }
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

#### getCommentAnnotations

* Subscribe to the comment annotations for all the specified documents.
* If you don't specify any query, it will return data from the currently set `documents` and `locations`.
* You can specify 30 documents at a time.
* **Params:** (optional) [CommentRequestQuery](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentrequestquery)
* **Returns:** [GetCommentAnnotationsResponse](https://velt.dev/docs/api-reference/sdk/models/data-models.md#getcommentannotationsresponse)

> [!NOTE]
>
> Available on SDK version 4.0.0 and above.

> [tab] React / Next.js
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const { data } = useGetCommentAnnotations(query);
>
> useEffect(() => {
>   if (data) {
>     // initial data value will be null while the request is in progress
>     console.log("Comment Annotations:", data);
>   }
> }, [data]);
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.getCommentAnnotations(query).subscribe((response) => {
>   // initial data value will be null while the request is in progress
>   console.log("Comment Annotations:", response.data);
> });
> ```

> [tab] Other Frameworks
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.getCommentAnnotations(query).subscribe((response) => {
>   // initial data value will be null while the request is in progress
>   console.log("Comment Annotations:", response.data);
> });
> ```

#### fetchCommentAnnotations

* Fetches comment annotations based on various criteria such as organizationId, folderId, or specific documentIds.
* It supports pagination and filtering options.
* This is different from the existing subscription API which subscribes to realtime changes to the comments data.
* Params: [FetchCommentAnnotationsRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#fetchcommentannotationsrequest)
* Returns: [FetchCommentAnnotationsResponse](https://velt.dev/docs/api-reference/sdk/models/data-models.md#fetchcommentannotationsresponse)

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Get all annotations for a specific folder
> const commentElement = client.getCommentElement();
> const response = await commentElement.fetchCommentAnnotations({
>   organizationId: 'org1', 
>   folderId: 'folder1',
>   allDocuments: true
> });
>
> // Get annotations for specific documents
> const response = await commentElement.fetchCommentAnnotations({
> organizationId: 'org1',
> documentIds: ['doc1', 'doc2']
> });
>
> // Get annotations with filters
> const response = await commentElement.fetchCommentAnnotations({
> organizationId: 'org1',
> documentIds: ['doc1', 'doc2'],
> createdAfter: 1234567890,
> statusIds: ['open'],
> pageSize: 20
> });
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> // Get all annotations for a specific folder
> const commentElement = Velt.getCommentElement();
> const response = await commentElement.fetchCommentAnnotations({
>   organizationId: 'org1',
>   folderId: 'folder1',
>   allDocuments: true
> });
>
> // Get annotations for specific documents
> const response = await commentElement.fetchCommentAnnotations({
>   organizationId: 'org1',
>   documentIds: ['doc1', 'doc2']
> });
>
> // Get annotations with filters
> const response = await commentElement.fetchCommentAnnotations({
>   organizationId: 'org1',
>   documentIds: ['doc1', 'doc2'],
>   createdAfter: 1234567890,
>   statusIds: ['open'],
>   pageSize: 20
> });
> ```

#### getSelectedComments

* Get the currently selected comment annotations.
* Returns: [`CommentAnnotation[]`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentannotation).

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> const subscription = commentElement
>   .getSelectedComments()
>   .subscribe((selectedComments) => {
>     console.log("Selected comments:", selectedComments);
>   });
> ```
>
> Unsubscribe from the subscription when you're done:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> const subscription = commentElement
>   .getSelectedComments()
>   .subscribe((selectedComments) => {
>     console.log("Selected comments:", selectedComments);
>   });
> ```
>
> Unsubscribe from the subscription when you're done:
>
> ```js theme={null}
> subscription?.unsubscribe();
> ```

#### getCommentAnnotationById

* Retrieve a specific comment annotation by its ID.
* By default, it will return the comment annotation for the current `documentId`.
* If you pass in a `documentId`, it will return the comment annotation for the given `documentId`.
* Returns: [CommentAnnotation](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentannotation)

> [tab] React / Next.js
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const annotation = useCommentAnnotationById({
>   annotationId: '-O6W3jD0Lz3rxuDuqQFx',  // AnnotationID
>   documentId: 'document-id'              // DocumentId (Optional)
> });
>
> useEffect(() => {
>   console.log('annotation', annotation);
> }, [annotation]);
> ```
>
> **Using API:**
>
> ```javascript theme={null}
> const commentElement = client.getCommentElement();
>
>     let subscription = commentElement.getCommentAnnotationById({
>       annotationId: '-O6W3jD0Lz3rxuDuqQFx',  // AnnotationID
>       documentId: 'document-id'              // DocumentId (Optional)
>     }).subscribe((annotation) => {
>       console.log('annotation', annotation);
>     });
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe()
> ```

> [tab] Other Frameworks
>
> **Using API:**
>
> ```javascript theme={null}
> const commentElement = Velt.getCommentElement();
>
> let subscription = commentElement.getCommentAnnotationById({
>   annotationId: '-O6W3jD0Lz3rxuDuqQFx',  // AnnotationID
>   documentId: 'document-id'              // DocumentId (Optional)
> }).subscribe((annotation) => {
>   console.log('annotation', annotation);
> });
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe()
> ```

#### getElementRefByAnnotationId

This will return the Xpath of the DOM element on which the comment was added.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> let elementRef = commentElement.getElementRefByAnnotationId("annotationId");
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> let elementRef = commentElement.getElementRefByAnnotationId('annotationId')
> ```

#### submitComment

Programmatically submit a comment from a composer. Enables custom buttons or keyboard shortcuts for submitting comments. The composer must have a `targetComposerElementId` set for this method to work.

* Params: [`SubmitCommentRequest`](https://velt.dev/docs/api-reference/sdk/models/data-models#submitcommentrequest)
* Returns: `void`
* See also: [Comment Composer targetComposerElementId](https://velt.dev/docs/async-collaboration/comments/standalone-components/comment-composer/customize-behavior.md)

> [tab] React / Next.js
>
> ```jsx theme={null}
>
> <VeltCommentComposer targetComposerElementId="composer-1" />
> <VeltCommentDialogComposer targetComposerElementId="composer-2" />
>
> // Using hook
> const commentElement = useCommentUtils();
> commentElement.submitComment({ targetComposerElementId: 'composer-1' });
>
> // Using API method
> const client = useVeltClient();
> const commentElement = client.getCommentElement();
> commentElement.submitComment({ targetComposerElementId: 'composer-1' });
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.submitComment({ targetComposerElementId: 'composer-1' });
> ```

#### clearComposer

Reset composer state including text, attachments, recordings, tagged users, assignments, and custom lists.

* Params: [`ClearComposerRequest`](https://velt.dev/docs/api-reference/sdk/models/data-models#clearcomposerrequest)
* Returns: `void`

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Hook
> const commentElement = useCommentUtils();
> commentElement.clearComposer({ targetComposerElementId: "composer-1" });
>
> // API Method
> const commentElement = client.getCommentElement();
> commentElement.clearComposer({ targetComposerElementId: "composer-1" });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.clearComposer({ targetComposerElementId: 'composer-1' });
> ```

#### getComposerData

Fetch current composer state on-demand. Returns same data structure as composerTextChange event.

* Params: [`GetComposerDataRequest`](https://velt.dev/docs/api-reference/sdk/models/data-models#getcomposerdatarequest)
* Returns: [`ComposerTextChangeEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#composertextchangeevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Hook
> const commentElement = useCommentUtils();
> const composerData = commentElement.getComposerData({
>   targetComposerElementId: "composer-1",
> });
>
> // API Method
> const commentElement = client.getCommentElement();
> const composerData = commentElement.getComposerData({
>   targetComposerElementId: "composer-1",
> });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> const composerData = commentElement.getComposerData({
>   targetComposerElementId: 'composer-1'
> });
> ```

#### markAsRead

* Mark a comment annotation as read for the current user. This updates the `viewedBy` field of the comment annotation to include the current user.
* Params: `annotationId: string`
* Returns: `Promise<void>`

> [tab] React / Next.js
>
> ```jsx theme={null}
> const markAsReadRequest = {
>   annotationId: "ANNOTATION_ID",
> };
>
> // Hook
> const { markAsRead } = useCommentUtils();
> await markAsRead(markAsReadRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> await commentElement.markAsRead(markAsReadRequest);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const markAsReadRequest = {
>   annotationId: "ANNOTATION_ID",
> };
>
> const commentElement = Velt.getCommentElement();
> await commentElement.markAsRead(markAsReadRequest);
> ```

#### markAsUnread

* Mark a comment annotation as unread for the current user. This removes the current user from the `viewedBy` field of the comment annotation.
* Params: `annotationId: string`
* Returns: `Promise<void>`

> [tab] React / Next.js
>
> ```jsx theme={null}
> const markAsUnreadRequest = {
>   annotationId: "ANNOTATION_ID",
> };
>
> // Hook
> const { markAsUnread } = useCommentUtils();
> await markAsUnread(markAsUnreadRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> await commentElement.markAsUnread(markAsUnreadRequest);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const markAsUnreadRequest = {
>   annotationId: "ANNOTATION_ID",
> };
>
> const commentElement = Velt.getCommentElement();
> await commentElement.markAsUnread(markAsUnreadRequest);
> ```

# Messages

#### addComment

* Add a comment to a specific comment annotation
* Params: [AddCommentRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addcommentrequest)
* Returns: [AddCommentEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addcommentevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const comment = {
>     commentText: 'This is a comment',
>     commentHtml: '<p>This is a comment</p>',
> };
>
> const addCommentRequest = {
> annotationId: 'ANNOTATION_ID',
> comment: comment
> };
>
> // Hook
> const { addComment } = useAddComment();
> const addCommentEventData = await addComment(addCommentRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const addCommentEventData = await commentElement.addComment(addCommentRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const comment = {
>     commentText: 'This is a comment',
>     commentHtml: '<p>This is a comment</p>',
> };
>
> const addCommentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   comment: comment
> };
>
> const commentElement = Velt.getCommentElement();
> const addCommentEventData = await commentElement.addComment(addCommentRequest);
> ```

#### updateComment

* Update a comment in a specific comment annotation
* Params: [UpdateCommentRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#updatecommentrequest)
* Returns: [UpdateCommentEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#updatecommentevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const comment = {
> 		commentId: 'COMMENT_ID',
>     commentText: 'This is a comment',
>     commentHtml: '<p>This is a comment</p>',
> };
>
> const updateCommentRequest = {
> annotationId: 'ANNOTATION_ID',
> comment: comment
> };
>
> // Hook
> const { updateComment } = useUpdateComment();
> const updateCommentEvent = await updateComment(updateCommentRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const updateCommentEvent = await commentElement.updateComment(updateCommentRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const comment = {
> 		commentId: 'COMMENT_ID',
>     commentText: 'This is a comment',
>     commentHtml: '<p>This is a comment</p>',
> };
>
> const updateCommentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   comment: comment
> };
>
> const commentElement = Velt.getCommentElement();
> const updateCommentEvent = await commentElement.updateComment(updateCommentRequest);
> ```

#### deleteComment

* Delete a comment from a specific comment annotation
* Params: [DeleteCommentRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deletecommentrequest)
* Returns: [DeleteCommentEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deletecommentevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const deleteCommentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   commentId: COMMENT_ID
> };
>
> // Hook
> const { deleteComment } = useDeleteComment();
> const deleteCommentEvent = await deleteComment(deleteCommentRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const deleteCommentEvent = await commentElement.deleteComment(deleteCommentRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const deleteCommentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   commentId: COMMENT_ID
> };
>
> const commentElement = Velt.getCommentElement();
> const deleteCommentEvent = await commentElement.deleteComment(deleteCommentRequest);
> ```

#### getComment

* Get comments from a specific comment annotation
* Params: [GetCommentRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#getcommentrequest)
* Returns: [Comment\[\]](https://velt.dev/docs/api-reference/sdk/models/data-models#comment)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const getCommentRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> // Hook
> const { getComment } = useGetComment();
> const comments = await getComment(getCommentRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const comments = await commentElement.getComment(getCommentRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const getCommentRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> const commentElement = Velt.getCommentElement();
> const comments = await commentElement.getComment(getCommentRequest);
> ```

#### getUnreadCommentCountOnCurrentDocument

> [tab] React / Next.js with Hooks
>
> You can get the number of unread `Comments` on the current `Document` by using the `useUnreadCommentCountOnCurrentDocument()` hook:
>
> ```jsx theme={null}
> const count = useUnreadCommentCountOnCurrentDocument();
> useEffect(() => {
>   console.log(count, "countObj");
> }, [count]);
> ```

> [tab] React / Next.js
>
> You can get the number of unread `Comments` on the current `Document` by using the `getUnreadCommentCountOnCurrentDocument()` method:
>
> ```jsx theme={null}
> if (client) {
>   const commentElement = client.getCommentElement();
>   let subscription = commentElement
>     .getUnreadCommentCountOnCurrentDocument()
>     .subscribe((countObj) => {
>       console.log(countObj);
>     });
> }
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

> [tab] Other Frameworks
>
> You can get the number of unread `Comments` on the current `Document` by using the `getUnreadCommentCountOnCurrentDocument()` method:
>
> ```jsx theme={null}
> if (Velt) {
>   const commentElement = Velt.getCommentElement();
>   let subscription = commentElement
>     .getUnreadCommentCountOnCurrentDocument()
>     .subscribe((countObj) => {
>       console.log(countObj);
>     });
> }
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

#### getUnreadCommentCountByLocationId

> [tab] React / Next.js with Hooks
>
> You can get the number of unread `Comments` by `Location Id` by using the `useUnreadCommentCountByLocationId()` hook:
>
> ```jsx theme={null}
> const count = useUnreadCommentCountByLocationId(locationId);
> useEffect(() => {
>   console.log(count, "countObj");
> }, [count]);
> ```

> [tab] React / Next.js
>
> You can get the number of unread `Comments` by `Location Id` by using the `getUnreadCommentCountByLocationId()` method:
>
> ```jsx theme={null}
> if (client) {
>   const commentElement = client.getCommentElement();
>   let subscription = commentElement
>     .getUnreadCommentCountByLocationId(locationId)
>     .subscribe((countObj) => {
>       console.log(countObj);
>     });
> }
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

> [tab] React / HTML
>
> You can get the number of unread `Comments` by `Location Id` by using the `getUnreadCommentCountByLocationId()` method:
>
> ```jsx theme={null}
> if (Velt) {
>   const commentElement = Velt.getCommentElement();
>   let subscription = commentElement
>     .getUnreadCommentCountByLocationId(locationId)
>     .subscribe((countObj) => {
>       console.log(countObj);
>     });
> }
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

#### getUnreadCommentCountByAnnotationId

> [tab] React / Next.js with Hooks
>
> You can get the number of unread `Comments` by annotation id by using the `useUnreadCommentCountByAnnotationId()` hook:
>
> ```jsx theme={null}
> const count = useUnreadCommentCountByAnnotationId(annotationId);
> useEffect(() => {
>   console.log(count, "countObj");
> }, [count]);
> ```

> [tab] React / Next.js
>
> You can get the number of unread `Comments` by annotation id by subscribing to the `getUnreadCommentCountByAnnotationId()` method:
>
> ```jsx theme={null}
> if (client) {
>   const commentElement = client.getCommentElement();
>   let subscription = commentElement
>     .getUnreadCommentCountByAnnotationId(annotationId)
>     .subscribe((countObj) => {
>       console.log(countObj);
>     });
> }
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

> [tab] Other Frameworks
>
> You can get the number of unread `Comments` by annotation id by subscribing to the `getUnreadCommentCountByAnnotationId()` method:
>
> ```jsx theme={null}
> if (Velt) {
>   const commentElement = Velt.getCommentElement();
>   let subscription = commentElement
>     .getUnreadCommentCountByAnnotationId(annotationId)
>     .subscribe((countObj) => {
>       console.log(countObj);
>     });
> }
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

# @Mentions

#### assignUser

* Assigns a user to a comment annotation
* Params: [AssignUserRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#assignuserrequest)
* Returns: [AssignUserEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#assignuserevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const assignUserRequest = {
>   annotationId: 'ANNOTATION_ID',
>   assignedTo: {
>     userId: 'USER_ID',
>     name: 'USER_NAME',
>     email: 'USER_EMAIL'
>   }
> };
>
> // Hook
> const { assignUser } = useAssignUser();
> const assignUserEventData = await assignUser(assignUserRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const assignUserEventData = await commentElement.assignUser(assignUserRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const assignUserRequest = {
>   annotationId: 'ANNOTATION_ID',
>   assignedTo: {
>     userId: 'USER_ID',
>     name: 'USER_NAME',
>     email: 'USER_EMAIL'
>   }
> };
>
> const commentElement = Velt.getCommentElement();
> const assignUserEventData = await commentElement.assignUser(assignUserRequest);
> ```

#### setAssignToType

Configure the assign-to UI mode as dropdown or checkbox.

API Method: [`setAssignToType()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#setassigntotype)

* Params: [`AssignToConfig`](https://velt.dev/docs/api-reference/sdk/models/data-models#assigntoconfig)
* Returns: `void`

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using props
> <VeltComments assignToType="checkbox" />
>
> // Using API methods
> const commentElement = useCommentUtils();
> commentElement.setAssignToType({ type: 'checkbox' }); // or 'dropdown'
>
> // Using API methods with client
> const commentElement = client.getCommentElement();
> commentElement.setAssignToType({ type: 'checkbox' }); // or 'dropdown'
>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments assign-to-type="checkbox"></velt-comments>
>
> <script>
> const commentElement = Velt.getCommentElement();
> commentElement.setAssignToType({ type: 'checkbox' }); // or 'dropdown'
> </script>
> ```

#### customAutocompleteSearch

* Handle autocomplete search for @mentions. You should use this if you have a large contact list that you want to plug into the autocomplete dropdown, and search directly your own data source.
* Event: [`AutocompleteSearchEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#autocompletesearchevent)

> [tab] React / Next.js
>
> **1. Enable the feature**
>
> ```jsx theme={null}
> // Enable via props
> <VeltComments customAutocompleteSearch={true} />
>
> // Or, enable via Comment Element API
> const commentElement = client.getCommentElement();
> commentElement.enableCustomAutocompleteSearch();
> commentElement.disableCustomAutocompleteSearch();
>
> ```
>
> **2. Set initial list**
>
> ```jsx theme={null}
> contactElement.updateContactList(users);
> ```
>
> **3. Handle search event**
>
> ```jsx theme={null}
> commentElement.on('autocompleteSearch').subscribe(async (inputData) => {
>     const searchText = inputData.searchText;
>
>     if (inputData.type === 'contact') {
>         const filteredUsersData = await __your_api_call__(searchText);
>         contactElement.updateContactList(filteredUsersData, { merge: false });
>     }
>
> });
>
> ```

> [tab] Other Frameworks
>
> **1. Enable the feature**
>
> ```js theme={null}
> // Enable via attribute
> <velt-comments custom-autocomplete-search="true"></velt-comments>
>
> // Or, enable via Comment Element API
> const commentElement = Velt.getCommentElement();
> commentElement.enableCustomAutocompleteSearch();
> commentElement.disableCustomAutocompleteSearch();
> ```
>
> **2. Set initial list**
>
> ```js theme={null}
> contactElement.updateContactList(users);
> ```
>
> **3. Handle search event**
>
> ```js theme={null}
> commentElement.on('autocompleteSearch').subscribe(async (inputData) => {
>     const searchText = inputData.searchText;
>
>     if (inputData.type === 'contact') {
>         const filteredUsersData = await __your_api_call__(searchText);
>         contactElement.updateContactList(filteredUsersData, { merge: false });
>     }
>
> });
>
> ```

#### enableAtHere

* This allows you to notify all the users explicitly added to the current document.
* It won't notify users in the organization who are not explicitly added to the document.

Default: Disabled.

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/enable-@-here.png?fit=max\&auto=format\&n=gAz_vLsG-ukKamYM\&q=85\&s=9adf0fac21313b3e73a0ee990a6c3330)

> [tab] React / Next.js
>
> **Hooks:**
>
> ```jsx theme={null}
> const contactElement = useContactUtils();
>
> useEffect(() => {
>   contactElement.enableAtHere();
>   contactElement.disableAtHere();
> }, [contactElement]);
>
> ```
>
> **API:**
>
> ```jsx theme={null}
> const contactElement = client.getContactElement();
> contactElement.enableAtHere();
> contactElement.disableAtHere();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const contactElement = Velt.getContactElement();
> contactElement.enableAtHere();
> contactElement.disableAtHere();
> ```

#### enableUserMentions

* This allows you to enable or disable user @mentions.

Whether user @mentions are enabled.

`Default: true`

> [tab] React / Next.js
>
> Using Props:
>
> ```jsx theme={null}
> <VeltComments userMentions={false} />
> ```
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const contactElement = useContactUtils();
>
> useEffect(() => {
>   contactElement.enableUserMentions();
>   contactElement.disableUserMentions();
> }, [contactElement]);
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const contactElement = client.getContactElement();
> contactElement.enableUserMentions();
> contactElement.disableUserMentions();
> ```

> [tab] Other Frameworks
>
> **Using props:**
>
> ```jsx theme={null}
> <velt-comments user-mentions="false"></velt-comments>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableUserMentions(); // to enable user mentions
> commentElement.disableUserMentions(); // to disable user mentions
> ```

#### enablePaginatedContactList

* Limits users downloaded for customers with thousands of users.
* Each contact list loads 10 users plus the signed-in user. An @mention search that matches fewer than 3 loaded contacts fetches more from the database.
* The `@here` option shows the document's full member count.
* Call `disablePaginatedContactList()` to load the full contact list up front. Both calls take effect at any time.

`Default: true`

> [tab] React / Next.js
>
> `paginatedContactList` is a prop on the `VeltComments` component. You don't import it separately.
>
> **Using Props:**
>
> ```jsx theme={null}
> import { VeltComments } from '@veltdev/react';
>
> <VeltComments paginatedContactList={false} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> import { useVeltClient } from '@veltdev/react';
>
> const { client } = useVeltClient();
> const commentElement = client.getCommentElement();
> commentElement.enablePaginatedContactList();
> commentElement.disablePaginatedContactList();
> ```

> [tab] Other Frameworks
>
> **Using HTML Attribute:**
>
> ```html theme={null}
> <velt-comments paginated-contact-list="false"></velt-comments>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enablePaginatedContactList();
> commentElement.disablePaginatedContactList();
> ```

#### anonymousEmail

* Controls whether unrecognized email addresses (not in the contact list) are resolved in the @mention flow.
* When disabled:
  * Freeform email addresses entered in the composer are ignored: they won’t show up in @mention suggestions, won’t be added to `taggedUserContacts`, and won’t be converted to contacts. However, known contacts (users matched from your contact list by email) will always appear, no matter this setting.
  * Notifications will not be sent to anonymous (unrecognized) email addresses.

`Default: true`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments anonymousEmail={false} />
> <VeltInlineCommentsSection anonymousEmail={false} />
> <VeltCommentDialog anonymousEmail={false} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableAnonymousEmail();
> commentElement.disableAnonymousEmail();
> ```

> [tab] Other Frameworks
>
> **Using HTML Attribute:**
>
> ```html theme={null}
> <velt-comments anonymous-email="false"></velt-comments>
> <velt-inline-comments-section target-element-id="article-body" anonymous-email="false"></velt-inline-comments-section>
> <velt-comment-dialog anonymous-email="false"></velt-comment-dialog>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableAnonymousEmail();
> commentElement.disableAnonymousEmail();
> ```

#### expandMentionGroups

* Expand the user groups and show individual users inside the groups in the @mentions dropdown menu.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments expandMentionGroups={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments expand-mention-groups="true"></velt-comments>
> ```

#### Mention Span CSS Classes

* When a user selects an @mention from the autocomplete dropdown, the inserted `<span>` element receives CSS classes that indicate the mention type.
* `velt-mention` is always present on every mention span.
* `velt-mention--name` is added when the mention is a user name.
* `velt-mention--email` is added when the mention is an email address.

Use these classes to apply distinct visual treatments to name vs. email mentions in the composer:

```css theme={null}
.velt-mention {
  font-weight: 600;
}
.velt-mention--name {
  color: #1a73e8;
}
.velt-mention--email {
  color: #7c3aed;
}
```

#### getContactList

* Subscribe to the list of users added to organization, folder, document, user groups or the ones overwritten using the `updateContactList` API.
* **Params:** none
* **Returns:** [GetContactListResponse](https://velt.dev/docs/api-reference/sdk/models/data-models.md#getcontactlistresponse)

> [tab] React / Next.js
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const contactList = useContactList();
> console.log(contactList); // initial value will be null
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const contactElement = useContactUtils();
> contactElement.getContactList().subscribe((response) => {
>   console.log(response); // initial value will be null
> });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const contactElement = Velt.getContactElement();
> contactElement.getContactList().subscribe((response) => {
>   console.log(response); // initial value will be null
> });
> ```

#### onContactSelected

* This event is triggered when a contact is selected from the contact dropdown in the Comment Dialog.
* Use the event object to determine if the selected contact has access to the document using fields like `isOrganizationContact`, `isDocumentContact` and `documentAccessType`.
* If the selected contact doesn't have access to the document, you can show an invite dialog to the user to invite the contact to the document.

The returned data will be in the following schema:

```jsx theme={null}
export class UserContactSelectedPayload {
    contact!: UserContact; // Selected Contact.
    isOrganizationContact!: boolean; // Is user part of organization contact.
    isDocumentContact!: boolean; // Is user part of document contact.
    documentAccessType!: string; // Document access type.
}
```

> [tab] React / Next.js
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const selectedContact = useContactSelected();
>
> useEffect(() => {
> console.log('selectedContact: ', selectedContact);
> }, [selectedContact]);
>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const contactElement = client.getContactElement();
>
> contactElement.onContactSelected().subscribe((selectedContact: any) => {
>   console.log('selectedContact : ', selectedContact);
> });
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const contactElement = Velt.getContactElement();
>
> contactElement.onContactSelected().subscribe((selectedContact: any) => {
> console.log('selectedContact: ', selectedContact);
> });
>
> ```

#### setAtHereLabel

* This allows you to modify the default text of the @here feature. e.g. @all, @everyone, @team, etc.

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments atHereLabel='@all'>
> ```
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const contactElement = useContactUtils();
>
> useEffect(() => {
>   contactElement.setAtHereLabel("@all");
> }, [contactElement]);
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const contactElement = client.getContactElement();
> contactElement.setAtHereLabel("@all");
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```jsx theme={null}
> <velt-comments at-here-label="@all">
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const contactElement = Velt.getContactElement();
> contactElement.setAtHereLabel("@all");
> ```

#### setAtHereDescription

* Customize the description that appears for the @here mention.

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments atHereDescription="Notify all users in this document" />
> ```
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const contactElement = useContactUtils();
>
> useEffect(() => {
>   contactElement.setAtHereDescription("Notify all users in this document");
> }, [contactElement]);
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const contactElement = client.getContactElement();
> contactElement.setAtHereDescription("Notify all users in this document");
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments
>   at-here-description="Notify all users in this document"
> ></velt-comments>
> ```
>
> **Using API Method:**
>
> ```javascript theme={null}
> const contactElement = Velt.getContactElement();
> contactElement.setAtHereDescription("Notify all users in this document");
> ```

#### showMentionGroupsFirst

* Show the user groups in the @mentions dropdown menu before the non-group users.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments showMentionGroupsFirst={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments show-mention-groups-first="true"></velt-comments>
> ```

#### showMentionGroupsOnly

* Show only the user groups in the @mentions dropdown menu and not the non-group users.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments showMentionGroupsOnly={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments show-mention-groups-only="true"></velt-comments>
> ```

#### subscribeCommentAnnotation

* Subscribes to a comment annotation
* Params: [SubscribeCommentAnnotationRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#subscribecommentannotationrequest)
* Returns: [SubscribeCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#subscribecommentannotationevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const subscribeCommentAnnotationRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> // Hook
> const { subscribeCommentAnnotation } = useSubscribeCommentAnnotation();
> const subscribeCommentAnnotationEvent = await subscribeCommentAnnotation(subscribeCommentAnnotationRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const subscribeCommentAnnotationEvent = await commentElement.subscribeCommentAnnotation(subscribeCommentAnnotationRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const subscribeCommentAnnotationRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> const commentElement = Velt.getCommentElement();
> const subscribeCommentAnnotationEvent = await commentElement.subscribeCommentAnnotation(subscribeCommentAnnotationRequest);
> ```

#### unsubscribeCommentAnnotation

* Unsubscribes from a comment annotation
* Params: [UnsubscribeCommentAnnotationRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#unsubscribecommentannotationrequest)
* Returns: [UnsubscribeCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#unsubscribecommentannotationevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const unsubscribeCommentAnnotationRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> // Hook
> const { unsubscribeCommentAnnotation } = useUnsubscribeCommentAnnotation();
> const unsubscribeCommentAnnotationEvent = await unsubscribeCommentAnnotation(unsubscribeCommentAnnotationRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const unsubscribeCommentAnnotationEvent = await commentElement.unsubscribeCommentAnnotation(unsubscribeCommentAnnotationRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const unsubscribeCommentAnnotationRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> const commentElement = Velt.getCommentElement();
> const unsubscribeCommentAnnotationEvent = await commentElement.unsubscribeCommentAnnotation(unsubscribeCommentAnnotationRequest);
> ```

#### updateContactList

* By default, the contact list is generated using the users in the organization and the document.
* However, if you do not want to use that feature or want to provide a custom list of contacts, you can use this method.
* By default, it will overwrite the current contact list. You can merge the provided contacts with the existing list by passing the merge flag as `{merge:true}`.
* When `filters: true` is passed, the sidebar People, Assigned, Tagged, and Involved filters are restricted to the custom contact list plus the current user.
* This method will only update the contact list in the current user session. It doesn't update the user contacts in the database or change the access control.

> [tab] React / Next.js
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const contactElement = useContactUtils();
>
> useEffect(() => {
> contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: false});
> }, [contactElement]);
>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const contactElement = client.getContactElement();
> contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: false});
> ```
>
> **Restrict sidebar filters to the contact list:**
>
> ```jsx theme={null}
> contactElement.updateContactList(contacts, { filters: true });
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const contactElement = Velt.getContactElement();
> contactElement.updateContactList([{userId: 'userId1', name: 'User Name', email: 'user1@velt.dev'}], {merge: false});
> ```
>
> **Restrict sidebar filters to the contact list:**
>
> ```jsx theme={null}
> contactElement.updateContactList(contacts, { filters: true });
> ```

#### updateOrgList

* Supplies the list of teams shown in the comment dialog's "Selected Teams" visibility picker.
* Takes an [`UpdateOrgListConfig`](https://velt.dev/docs/api-reference/sdk/models/data-models#updateorglistconfig) whose `orgList` is an array of [`OrgContact`](https://velt.dev/docs/api-reference/sdk/models/data-models#orgcontact) (`{ id, name? }`).
* Unlike `updateContactList`, this is a full replace on every call (it does not merge). Pass `{ orgList: [] }` to clear the picker and revert the banner option to "Your Team".
* Exposed on `contactElement` only.

> [tab] React / Next.js
>
> ```tsx theme={null}
> import { useVeltClient } from '@veltdev/react';
> import { useEffect } from 'react';
>
> export default function SetTeams() {
>   const { client } = useVeltClient();
>   useEffect(() => {
>     if (!client) return;
>     const contactElement = client.getContactElement();
>     contactElement.updateOrgList({
>       orgList: [
>         { id: 'team-eng', name: 'Team Eng' },
>         { id: 'team-design', name: 'Design' },
>         { id: 'team-ops', name: 'Operations' },
>       ],
>     });
>   }, [client]);
>   return null;
> }
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <script>
>   const contactElement = Velt.getContactElement();
>   contactElement.updateOrgList({
>     orgList: [
>       { id: 'team-eng', name: 'Team Eng' },
>       { id: 'team-design', name: 'Design' },
>       { id: 'team-ops', name: 'Operations' },
>     ],
>   });
>   // Clear the picker (revert the banner option to "Your Team"):
>   contactElement.updateOrgList({ orgList: [] });
> </script>
> ```

#### updateContactListScopeForOrganizationUsers

* Sometimes you may want to show only certain types of contacts in the contact dropdown.
* By default, organization users will see all contacts in the organization, any user groups and any contacts added to the document.
* Using this method, you can restrict the contacts shown in the dropdown to only certain types.
* This only affects the Organization Users and not the Document Users. Document Users will always only see contacts added to the document.

Here are the available options:

* `all`: Show all the contacts
* `organization`: Show organization contacts.
* `organizationUserGroup`: Show organization user groups.
* `document`: Show document contacts.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const contactElement = client.getContactElement();
> contactElement.updateContactListScopeForOrganizationUsers(['all', 'organization', 'organizationUserGroup', 'document']);
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const contactElement = Velt.getContactElement();
> contactElement.updateContactListScopeForOrganizationUsers(['all', 'organization', 'organizationUserGroup', 'document']);
> ```

#### [setAnonymousUserDataProvider](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#setanonymoususerdataprovider)

Register a provider to resolve email → `userId` mappings for users who are tagged by email in comments but are not part of the contact list. When a comment is saved and a tagged contact or `to` recipient has an email but no `userId`, the SDK calls the provider to look up the `userId` and backfills it into the comment data before persisting.

[Full implementation guide →](https://velt.dev/docs/self-hosting/partial/users.md#anonymous-user-resolution)

#### autoCompleteScrollConfig

Customize virtual scroll behavior in autocomplete dropdown for @mentions.

Type: [`AutoCompleteScrollConfig`](https://velt.dev/docs/api-reference/sdk/models/data-models#autocompletescrollconfig)

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments
>   autoCompleteScrollConfig={{
>     itemSize: 28,
>     minBufferPx: 100,
>     maxBufferPx: 200,
>     templateCacheSize: 20,
>   }}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments
>   autocomplete-scrollconfig='{
> "itemSize": 28,
> "minBufferPx": 100,
> "maxBufferPx": 200,
> "templateCacheSize": 20
> }'
> ></velt-comments>
> ```

# Metadata

#### addContext

Custom metadata allows you to add extra information to comments, enhancing their functionality. Here's what you can do with it:

* Render additional data on comments
* Position comment pins manually
* Create custom UI components
* Enable comment filtering on custom data

To add custom metadata, use one of the following events which has the `addContext` method. This method accepts an object with key-value pairs.

* `addCommentAnnotationDraft`
* `addCommentAnnotation`

Alternatively, you can pass `context` as a prop to most components that helps with creating new comment annotations. Eg:

* `VeltCommentTool`
* `VeltCommentComposer`
* `VeltCommentDialogComposer`
* `VeltInlineCommentsSection`

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/images/addContext.png?fit=max\&auto=format\&n=gAz_vLsG-ukKamYM\&q=85\&s=7fcc3569ff4420fb7652f1124239cd89)

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Hook
> const commentEventCallbackData = useCommentEventCallback('addCommentAnnotation');
> useEffect(() => {
>   if (commentEventCallbackData) {
>     commentEventCallbackData.addContext({ customKey: 'customValue' });
>   }
> }, [commentEventCallbackData]);
>
> // API Method
> const commentElement = client.getCommentElement();
> commentElement.on('addCommentAnnotation').subscribe((event) => {
> event.addContext({ customKey: 'customValue' });
> });
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.on('addCommentAnnotation').subscribe((event) => {
>     event.addContext({ customKey: 'customValue' });
> });
> ```

#### updateContext

* Update the custom metadata associated with a comment annotation using the `updateContext` method.
* Utilize this method to update the context of a comment annotation at any time. For example, you might use this when the name of the dashboard containing the comment annotation changes.

The `commentElement.updateContext()` method accepts three parameters:

* The Comment Annotation ID
* The new metadata object
* An optional `updateContextConfig` object. Specify how the new metadata should be applied:
  * `{ merge: true }`: Merges the new metadata with the existing metadata
  * `{ merge: false }` or omitted: Replaces the existing metadata entirely (default behavior)

> [tab] React / Next.js
>
> Using API:
>
> ```js theme={null}
> const updatedContext = { customKey: "customValue" };
> const updateContextConfig = { merge: true };
>
> const commentElement = client.getCommentElement();
> commentElement.updateContext(
>   COMMENT_ANNOTATION_ID,
>   updatedContext,
>   updateContextConfig,
> );
> ```

> [tab] Other Frameworks
>
> Using API method:
>
> ```js theme={null}
> const updatedContext = { customKey: "customValue" };
> const updateContextConfig = { merge: true };
>
> const commentElement = client.getCommentElement();
> commentElement.updateContext(
>   COMMENT_ANNOTATION_ID,
>   updatedContext,
>   updateContextConfig,
> );
> ```

#### setContextProvider

Provide custom context (metadata) dynamically for comments using a provider function. This method allows you to return context based on the document and location where a comment is being added.
The SDK will call this function whenever a new comment annotation is created so you can provide dynamic values for the context.

The provider function receives `documentId` and optional `location` parameters and can return a [`CommentContext`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentcontext) object, `null`, `undefined`, or a Promise resolving to any of these values.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Hook
> import { useCallback, useEffect } from 'react';
> import { useSetContextProvider } from '@veltdev/react';
>
> const contextProvider = useCallback((documentId, location) => {
> return {
> customKey: 'customValue'
> };
> }, []);
>
> const { setContextProvider } = useSetContextProvider();
>
> useEffect(() => {
> if (setContextProvider && contextProvider) {
> setContextProvider(contextProvider);
> }
> }, []);
>
> // API Method
> const commentElement = client.getCommentElement();
> commentElement.setContextProvider((documentId, location) => {
> return {
> customKey: 'customValue'
> };
> });
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setContextProvider((documentId, location) => {
>   return {
>     customKey: 'customValue'
>   };
> });
> ```

#### setContextInPageModeComposer

Set context data for the page mode composer programmatically.

Accepts a [`PageModeComposerConfig`](https://velt.dev/docs/api-reference/sdk/models/data-models#pagemodecomposerconfig) object. Pass custom context data that will be included when a comment is created through the page mode composer.

API Method: [`setContextInPageModeComposer()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#setcontextinpagemodecomposer)

> [!NOTE]
>
> For automatic context passing when opening the comment sidebar via the comment
> tool, see [contextInPageModeComposer](#contextinpagemodecomposer).

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using Hook
> const commentElement = useCommentUtils();
>
> // Set context with optional target element
> commentElement.setContextInPageModeComposer({
> context: { documentId: 'doc-123', section: 'intro' },
> targetElementId: 'element-1'
> });
>
> // Using API Method
> const commentElement = client.getCommentElement();
> commentElement.setContextInPageModeComposer({
> context: { documentId: 'doc-123', section: 'intro' },
> targetElementId: 'element-1'
> });
>
> // Set only context without target element
> commentElement.setContextInPageModeComposer({
> context: { documentId: 'doc-123' }
> });
>
> // Clear the context and target element
> commentElement.setContextInPageModeComposer({
> context: null,
> targetElementId: null
> });
>
> // Preserve context after submission
> commentElement.setContextInPageModeComposer({
> context: { documentId: 'doc-123', section: 'intro' },
> targetElementId: 'element-1',
> clearContext: false
> });
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
>
> // Set context with optional target element
> commentElement.setContextInPageModeComposer({
>   context: { documentId: 'doc-123', section: 'intro' },
>   targetElementId: 'element-1'
> });
>
> // Set only context without target element
> commentElement.setContextInPageModeComposer({
>   context: { documentId: 'doc-123' }
> });
>
> // Clear the context and target element
> commentElement.setContextInPageModeComposer({
>   context: null,
>   targetElementId: null
> });
>
> // Preserve context after submission
> commentElement.setContextInPageModeComposer({
>   context: { documentId: 'doc-123', section: 'intro' },
>   targetElementId: 'element-1',
>   clearContext: false
> });
> ```

#### clearPageModeComposerContext

Clear context data from page mode composer. This is useful when you are using sidebar in embed mode and have to clear the context from page mode composer manually.

API Method: [`clearPageModeComposerContext()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#clearpagemodecomposercontext)

* Params: none
* Returns: `void`

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.clearPageModeComposerContext();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <script>
>   const commentElement = Velt.getCommentElement();
>   commentElement.clearPageModeComposerContext();
> </script>
> ```

# Aggregation

### Overview

**Aggregation** lets you filter, group, and render comments that match specific criteria, without writing any custom logic.\
It's especially powerful when comments are tied to structured data such as products, categories, or financial entities.

You can group comments by:

* Metadata (`context`)
* Element IDs (`targetElementId`)
* Resource identifiers (`documentId`, `folderId`, `locationId`)

In short: aggregation helps you **query comments like data**.

***

### When to Use Aggregation

Use aggregation when your app involves complex relationships or taxonomy-based filtering.

#### 🧩 Tables & Dashboards

**Supply Chain Example**\
A product can belong to multiple categories. When viewing data by category, you may want to display all comments made on products within that category, or even across product variants.

**Financial Planning Example**\
A budget item (e.g., *Marketing Q1*) can have multiple subcategories (e.g., *Paid Ads*, *Sponsorships*).\
Aggregation allows you to show all comments related to a specific period, department, or account group, even if those comments live across different documents or views.

***

### How It Works

#### Comment Metadata Fields

Each comment can include one or more of the following identifiers or metadata fields:

| Field | Description |
| - | - |
| `folderId` | Target folder ID |
| `documentId` | Target document ID |
| `locationId` | Target location ID |
| `targetElementId` | Target DOM element ID |
| `context` | Custom metadata object for grouping or filtering |

***

#### Comment Creation

When you use any of the above identifiers or metadata fields in the following supported components, they automatically get **attached to the comment** at the time it's created.\
This ensures that each comment carries the correct folder, document, element, or context metadata, so it can later be filtered or grouped accurately.

**Supported Components**

* Inline Comments Section
* Comment Tool

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Comment Tool with context metadata
> <VeltCommentTool
>   targetElementId="cell-jan-cheese-zurich"
>   context={{
>     month: "jan",
>     year: "2024",
>     product: "cheese",
>     location: "zurich"
>   }}
> />
>
> // Inline Comments Section with context
>
> <VeltInlineCommentsSection
>   targetElementId="budget-item-marketing-q1"
>   context={{
>     department: "marketing",
>     quarter: "Q1",
>     category: "paid-ads"
>   }}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Comment Tool with context metadata -->
> <velt-comment-tool
>   target-element-id="cell-jan-cheese-zurich"
>   context='{
>     "month": "jan",
>     "year": "2024",
>     "product": "cheese",
>     "location": "zurich"
>   }'
> >
> </velt-comment-tool>
>
> <!-- Inline Comments Section with context -->
>
> <velt-inline-comments-section
> target-element-id="budget-item-marketing-q1"
> context='{
> "department": "marketing",
> "quarter": "Q1",
> "category": "paid-ads"
> }'
>
> > </velt-inline-comments-section>
>
> ```

***

#### Comment Rendering

When the above identifiers or metadata fields are passed to the following rendering components, they determine **which comments are displayed**.
Only comments that match the provided folder, document, element, or context values will be rendered in that component.

**Supported Components**

* Comment Bubble
* Inline Comments Section
* Comment Pin (Standalone) — *does not support* `targetElementId`

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Comment Bubble - filter by context
> <VeltCommentBubble
>   context={{ product: "cheese" }}
>   contextOptions={{ partialMatch: true }}
> />
>
> // Comment Bubble - filter by target element
> <VeltCommentBubble targetElementId="cell-jan-cheese-zurich" />
>
> // Inline Comments Section - filter by context
> <VeltInlineCommentsSection
>   context={{ department: "marketing" }}
>   contextOptions={{ partialMatch: true }}
> />
>
> // Comment Pin - filter by context (no targetElementId support)
> <VeltCommentPin
>   context={{ product: "cheese", month: "jan" }}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Comment Bubble - filter by context -->
> <velt-comment-bubble
>   context='{ "product": "cheese" }'
>   context-options='{ "partialMatch": true }'
> >
> </velt-comment-bubble>
>
> <!-- Comment Bubble - filter by target element -->
>
> <velt-comment-bubble target-element-id="cell-jan-cheese-zurich"></velt-comment-bubble>
>
> <!-- Inline Comments Section - filter by context -->
>
> <velt-inline-comments-section
> context='{ "department": "marketing" }'
> context-options='{ "partialMatch": true }'
>
> > </velt-inline-comments-section>
>
> <!-- Comment Pin - filter by context (no targetElementId support) -->
>
> <velt-comment-pin
> context='{ "product": "cheese", "month": "jan" }'
>
> > </velt-comment-pin>
>
> ```

***

### Filtering Behavior

When filtering comments, only annotations matching **all provided fields** will be shown:

```

folderId
documentId
locationId
targetElementId
context

```

***

### `Context` Matching

You can choose between two matching modes for the `context` field: **Full Match** (default) or **Partial Match**.

***

#### 🔒 Full Match (Default)

A comment matches **only if all fields** in its context exactly match your filter criteria.

**Example:**

```js theme={null}
// Comment context
{ month: "jan", product: "cheese", location: "zurich" }

// Filters
{ month: "jan", product: "cheese", location: "zurich" }  ✅ Matches
{ month: "jan", product: "cheese" }                      ❌ No match (missing field)
{ month: "jan", product: "cheese", year: "2024" }        ❌ No match (extra field)
```

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Full match (default)
> <VeltCommentBubble
>   context={{ month: "jan", product: "cheese", location: "zurich" }}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Full match (default) -->
> <velt-comment-bubble
>   context='{ "month": "jan", "product": "cheese", "location": "zurich" }'
> >
> </velt-comment-bubble>
> ```

***

#### 🔍 Partial Match

Enable partial matching with `contextOptions={{ partialMatch: true }}`.

A comment matches if **all fields in your filter exist in the comment's context**.\
Extra fields in the comment context don't prevent a match.

**Example:**

```js theme={null}
// Comment context
{ day: "01", week: "01", month: "jan", product: "cheese", location: "zurich" }

// Filters
{ product: "cheese" }                   ✅ Matches
{ day: "01", product: "cheese" }        ✅ Matches
{ product: "cheese", category: "dairy"} ❌ No match (missing field)
```

**Example**

> [tab] React / Next.js
>
> ```jsx theme={null}
> {/* Comment Bubble with Partial Match */}
> <VeltCommentBubble
>   context={{ product: "cheese" }}
>   contextOptions={{ partialMatch: true }}
> />
>
> {/* Comment Tool with Partial Match */}
>
> <VeltCommentTool
>   targetElementId="element_id"
>   context={{ product: "cheese" }}
>   contextOptions={{ partialMatch: true }}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Comment Bubble with Partial Match -->
> <velt-comment-bubble
>   context='{ "product": "cheese" }'
>   context-options='{ "partialMatch": true }'
> >
> </velt-comment-bubble>
>
> <!-- Comment Tool with Partial Match -->
>
> <velt-comment-tool
> target-element-id="element_id"
> context='{ "product": "cheese" }'
> context-options='{ "partialMatch": true }'
>
> > </velt-comment-tool>
>
> ```

***

### Grouping Matched Comment Annotations

When multiple comments match your filter criteria, you can **group them** into a single visual element — such as a Comment Bubble, Comment Pin, or Inline Comments Section — for a cleaner, multi-threaded UI.

**How it works:**

* Enable grouping globally with `groupMatchedComments`
* All matching annotations are shown as one grouped thread
* The comment count shows total grouped annotations
* Users can expand to view and interact with all related threads

**Example**

If there are three comments for `"product: cheese"` across different months, they can all appear in one Comment Bubble when you filter by `{ product: "cheese" }`.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Enable grouping globally
> <VeltComments groupMatchedComments={true} />
>
> // Grouped Comment Bubble
> <VeltCommentBubble
>   context={{ product: "cheese" }}
>   contextOptions={{ partialMatch: true }}
> />
>
> // Enable/disable via API
> const commentElement = client.getCommentElement();
> commentElement.enableGroupMatchedComments();
> commentElement.disableGroupMatchedComments();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Enable grouping globally -->
> <velt-comments group-matched-comments="true"></velt-comments>
>
> <!-- Grouped Comment Bubble -->
>
> <velt-comment-bubble
> context='{ "product": "cheese" }'
> context-options='{ "partialMatch": true }'
> comment-count-type="total"
>
> > </velt-comment-bubble>
>
> <script>
>   const commentElement = Velt.getCommentElement();
>   commentElement.enableGroupMatchedComments();
>   commentElement.disableGroupMatchedComments();
> </script>
>
> ```

***

# Private Comments (beta)

> [!NOTE]
>
> The visibility system uses two separate sets of values:
>
> * **API methods** (on this page) use [`CommentVisibilityConfig`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentvisibilityconfig) with 3 values: `'public'`, `'organizationPrivate'`, `'restricted'`.
> * **UI wireframes** use the [`CommentVisibilityOption`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentvisibilityoption) enum with 4 values: `'restrictedSelf'`, `'restrictedSelectedPeople'`, `'organizationPrivate'`, `'public'`.
>
> The API's single `'restricted'` value covers both "self-only" and "selected people", distinguished by whether `userIds` is provided.

To use this feature, you need to first **enable** it in [Velt Console](https://console.velt.dev/dashboard/config/appconfig).

#### [updateVisibility](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#updatevisibility)

Manage who can view a comment annotation by updating its visibility settings. Use this method to control whether a comment is public, restricted to your organization, or visible only to specific users. The resulting setting is stored on the annotation as [`visibilityConfig`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentannotationvisibilityconfig).

* To use this feature, you need to first enable it in [Velt Console](https://console.velt.dev/dashboard/config/appconfig)
* Params: [CommentVisibilityConfig](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentvisibilityconfig)
  * `type`:
    * `'public'`: Comment visible to all users
    * `'organizationPrivate'`: Comment visible only to users in the specified organization. Even if someone is added to the document but not to the organization, they will not be able to view the comment.
    * `'restricted'`: Comment visible only to the specified users; the current user is always included
  * `organizationId`: string; used when `type` is `organizationPrivate`
  * `organizationIds`: string\[]; optional when `type` is `'organizationPrivate'` — target multiple orgs; merged + de-duplicated with `organizationId`. With neither provided, the comment defaults to the logged-in user's own org.
  * `userIds`: string\[]; optional when `type` is `'restricted'` — current user is always appended
* Returns: `void`

> [!NOTE]
>
> When `type` is `'restricted'`, the SDK automatically appends the current user's `userId` to `userIds` if it is not already present. This applies whether `userIds` is empty or contains an explicit list that excludes the author.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
>
> // Set comment to be visible only to the organization
> commentElement.updateVisibility({
>   annotationId: "annotationId",
>   type: 'organizationPrivate',
>   organizationId: 'org-123'
> });
>
> // Set comment to be visible to multiple organizations / teams
> commentElement.updateVisibility({
>   annotationId: "annotationId",
>   type: 'organizationPrivate',
>   organizationIds: ['org-A', 'org-B']
> });
>
> // Set comment to be private (current user always included in restricted access)
> commentElement.updateVisibility({
>   annotationId: "annotationId",
>   type: 'restricted'
> });
>
> // Set comment to be private (visible only to specific users)
> commentElement.updateVisibility({
>   annotationId: "annotationId",
>   type: 'restricted',
>   userIds: ['user-1', 'user-2']
> });
>
> // Set comment to be public
> commentElement.updateVisibility({
>   annotationId: "annotationId",
>   type: 'public'
> });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
>
> // Set comment to be visible only to the organization
> commentElement.updateVisibility({
> annotationId: "annotationId",
> type: 'organizationPrivate',
> organizationId: 'org-123'
> });
>
> // Set comment to be visible to multiple organizations / teams
> commentElement.updateVisibility({
> annotationId: "annotationId",
> type: 'organizationPrivate',
> organizationIds: ['org-A', 'org-B']
> });
>
> // Set comment to be private (current user always included in restricted access)
> commentElement.updateVisibility({
> annotationId: "annotationId",
> type: 'restricted'
> });
>
> // Set comment to be private (visible only to specific users)
> commentElement.updateVisibility({
> annotationId: "annotationId",
> type: 'restricted',
> userIds: ['user-1', 'user-2']
> });
>
> // Set comment to be public
> commentElement.updateVisibility({
> annotationId: "annotationId",
> type: 'public'
> });
>
> ```

#### [enablePrivateMode](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#enableprivatemode)

Set the default visibility for all new comments created by the current user.

* Params: [PrivateModeConfig](https://velt.dev/docs/api-reference/sdk/models/data-models.md#privatemodeconfig)
  * `type`:
    * `'restricted'`: New comments visible only to the specified users; the current user is always included
    * `'organizationPrivate'`: New comments visible only to users in the current organization
  * `organizationId`: string; optional when `type` is `'organizationPrivate'`
  * `organizationIds`: string\[]; optional when `type` is `'organizationPrivate'` — target multiple orgs; merged + de-duplicated with `organizationId`. With neither provided, comments default to the logged-in user's own org.
  * `userIds`: string\[]; optional when `type` is `'restricted'` — current user is always appended
* Returns: `void`

> [!NOTE]
>
> When `type` is `'restricted'`, the SDK automatically appends the current user's `userId` to `userIds` if it is not already present. This applies whether `userIds` is empty or contains an explicit list that excludes the author.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> // Restrict all new comments to specific users
> commentElement.enablePrivateMode({ type: 'restricted', userIds: ['user-1', 'user-2'] });
> // Restrict all new comments to the current organization
> commentElement.enablePrivateMode({ type: 'organizationPrivate' });
> // Restrict all new comments to multiple organizations / teams
> commentElement.enablePrivateMode({ type: 'organizationPrivate', organizationIds: ['org-A', 'org-B'] });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> // Restrict all new comments to specific users
> commentElement.enablePrivateMode({ type: 'restricted', userIds: ['user-1', 'user-2'] });
> // Restrict all new comments to the current organization
> commentElement.enablePrivateMode({ type: 'organizationPrivate' });
> // Restrict all new comments to multiple organizations / teams
> commentElement.enablePrivateMode({ type: 'organizationPrivate', organizationIds: ['org-A', 'org-B'] });
> ```

#### [disablePrivateMode](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#disableprivatemode)

Revert new comment visibility to default public visibility.

* Returns: `void`

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> // Revert to default public visibility
> commentElement.disablePrivateMode();
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> // Revert to default public visibility
> commentElement.disablePrivateMode();
> ```

#### visibilityOptions

Show a visibility banner on the comment composer that lets users set a comment's visibility to `public`, `organization-private`, `restricted-self`, or `restricted` before submitting. Users can also change visibility after submission from the thread options menu.

Default: `false`

> [!NOTE]
>
> Enable **Private Comments** in the [Velt Console](https://console.velt.dev/dashboard/config/appconfig) before turning this on. Without the Console setting, the "Visible to" dropdown does not filter the audience: comments stay visible to everyone on the document even after a user picks a non-public option. `updateVisibility()` and `enablePrivateMode()` have the same requirement.

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments visibilityOptions={true} />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableVisibilityOptions();
> commentElement.disableVisibilityOptions();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments visibility-options="true"></velt-comments>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableVisibilityOptions();
> commentElement.disableVisibilityOptions();
> ```

#### visibilityOptionClicked

Subscribe to this event to be notified when a user selects a visibility option. Emits a [`VisibilityOptionClickedEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#visibilityoptionclickedevent).

#### Setting visibility at comment creation time

If you are creating comments using API, then pass a [`CommentVisibilityConfig`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentvisibilityconfig) as the optional `visibility` field on [`AddCommentRequest`](https://velt.dev/docs/api-reference/sdk/models/data-models#addcommentrequest) to pre-set visibility when programmatically adding a comment.

> [tab] React / Next.js
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const addCommentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   comment: {
>     commentText: 'This is a comment',
>     commentHtml: '<p>This is a comment</p>',
>   },
>   visibility: {
>     type: 'restricted',
>     userIds: ['user-1', 'user-2']
>   }
> };
>
> const { addComment } = useAddComment();
> const addCommentEventData = await addComment(addCommentRequest);
>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const addCommentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   comment: {
>     commentText: 'This is a comment',
>     commentHtml: '<p>This is a comment</p>',
>   },
>   visibility: {
>     type: 'restricted',
>     userIds: ['user-1', 'user-2']
>   }
> };
>
> const commentElement = client.getCommentElement();
> const addCommentEventData = await commentElement.addComment(addCommentRequest);
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const addCommentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   comment: {
>     commentText: 'This is a comment',
>     commentHtml: '<p>This is a comment</p>',
>   },
>   visibility: {
>     type: 'restricted',
>     userIds: ['user-1', 'user-2']
>   }
> };
>
> const commentElement = Velt.getCommentElement();
> const addCommentEventData = await commentElement.addComment(addCommentRequest);
>
> ```

#### Private comments with Access Context

Comments have two independent scoping systems. A comment can carry both at the same time.

* **Visibility** controls who is allowed to see a comment. Set it with [`updateVisibility()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#updatevisibility), [`enablePrivateMode()`](#enableprivatemode), or the composer visibility banner. The result is stored on the annotation as [`visibilityConfig`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentannotationvisibilityconfig).
* **Access Context** partitions comments by custom metadata. Attach it with [`addContext()`](#addcontext) or [`setContextProvider()`](#setcontextprovider), then set `isContextEnabled: true` on your Permission Provider. See [Set Feature Level Permissions using Access Context](https://velt.dev/docs/key-concepts/overview.md#d-set-feature-level-permissions-using-access-context).

Velt enforces the two systems separately. A viewer must pass both checks to see the comment. No integration change required.

This example attaches an Access Context to every new comment and restricts those comments to the current organization:

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Hook
> import { useEffect } from 'react';
> import { useSetContextProvider } from '@veltdev/react';
>
> const { setContextProvider } = useSetContextProvider();
>
> useEffect(() => {
>   if (setContextProvider) {
>     // Attach an Access Context to every new comment
>     setContextProvider(() => ({
>       access: { widgetId: 2 }
>     }));
>   }
> }, [setContextProvider]);
>
> // API Method
> const commentElement = client.getCommentElement();
>
> // Attach an Access Context to every new comment
> commentElement.setContextProvider(() => ({
>   access: { widgetId: 2 }
> }));
>
> // Restrict every new comment to the current organization
> commentElement.enablePrivateMode({ type: 'organizationPrivate' });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
>
> // Attach an Access Context to every new comment
> commentElement.setContextProvider(() => ({
>   access: { widgetId: 2 }
> }));
>
> // Restrict every new comment to the current organization
> commentElement.enablePrivateMode({ type: 'organizationPrivate' });
> ```

**How the two settings behave together**

* Making a comment private keeps its Access Context. The comment stays scoped to the same context values.
* Updating a comment's Access Context with [`updateContext()`](#updatecontext) keeps its visibility. A private comment stays private, including when you clear the access object by passing `null`.
* You can edit a private comment while Access Context is enabled.
* Comments created with an Access Context set outside the [`addContext()`](#addcontext) event callback now load right away and still appear after a reload. This covers [`setContextProvider()`](#setcontextprovider) and the `context` prop on components such as `VeltCommentTool` and `VeltCommentComposer`. Comments created with `addContext()` were never affected.
* A private comment reaches only the users its visibility allows. Viewers in the same Access Context who are not on that list never receive it.
* A private comment appears only under its own Access Context, for everyone including the author. Context is a data partition, not a permission.
* Turning an already loaded comment private removes it from other viewers' screens right away. Previously the stale copy stayed on screen until they reloaded.
* Turning a comment back to public keeps it loadable when Access Context is turned off.
* Organization members keep seeing the comments already restricted to their organization, even after you turn the Private Comments feature off in the [Velt Console](https://console.velt.dev/dashboard/config/appconfig). Previously those comments could disappear for them.

**Reactions, recordings, and area annotations**

These child items do not inherit their parent comment's Access Context when the parent comment is private.

* Velt does not copy the parent's Access Context onto them, so Access Context does not scope them.
* Viewers in the same Access Context who cannot see the parent comment no longer receive them.

> [!NOTE]
>
> **Reserved names.** Do not name an Access Context field `organizationPrivate`. Velt reads that field as a visibility setting, so the comment loads for the wrong users. Velt does not block the name at runtime, so check it on your side. [Learn more →](https://velt.dev/docs/key-concepts/overview.md#d-set-feature-level-permissions-using-access-context)

#### Notifications for private comments

Comment notifications follow the comment's visibility. A user who cannot see a private comment gets no notification for it, on any channel. Velt sends no redacted placeholder. The comment author and any user or organization named in the comment's visibility normally receive the notification. No API change.

[Learn more →](https://velt.dev/docs/async-collaboration/notifications/overview.md#notifications-for-private-comments)

# Custom Lists

#### createCustomListDataOnAnnotation

* Add a custom dropdown list at the Comment Annotation level.
* Use this to add custom tags or categories to the comment.

![](https://mintcdn.com/velt/2O8vk8YlVD4Kq-ni/images/customization/comment-annotation-custom-list.png?fit=max\&auto=format\&n=2O8vk8YlVD4Kq-ni\&q=85\&s=49e69684842120873f9f58d5874f42d2)

```jsx theme={null}
let customList = [
    { id: 'violent', label: 'Violent' },
    { id: 'inappropriate', label: 'Inappropriate' },
    { id: 'robbery', label: 'Robbery' },
    { id: 'nsfw', label: 'NSFW' },
];

const customListDataOnCommentAnnotation = {
	  type: 'multi', // choose from 'multi' or 'single'
    placeholder: 'Select a category',
    data: customList, // your customList data here
};
```

> [tab] React / Next.js with hooks
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments customListDataOnAnnotation={customListDataOnCommentAnnotation} />
> ```
>
> **API Method:**
>
> ```jsx theme={null}
> const commentElement = useCommentUtils();
> commentElement.createCustomListDataOnAnnotation(
>   customListDataOnCommentAnnotation,
> );
> ```

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments customListDataOnAnnotation={customListDataOnCommentAnnotation} />
> ```
>
> **API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.createCustomListDataOnAnnotation(
>   customListDataOnCommentAnnotation,
> );
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();			
> commentElement.createCustomListDataOnAnnotation(customListDataOnCommentAnnotation);
> ```

#### createCustomListDataOnComment

You can have custom dropdown lists appear when certain `hotkeys` are pressed.

When you press a hotkey inside the Comment Dialog composer, it will open a dropdown list of items that you can select.

![](https://mintcdn.com/velt/y_bUi9B-cnWLxN8L/images/customization/custom-list-1.png?fit=max\&auto=format\&n=y_bUi9B-cnWLxN8L\&q=85\&s=6f03afec1c52499cf210ef46c44af51b)

Selecting an item from the dropdown list will add a chip inside the comment text.

![](https://mintcdn.com/velt/y_bUi9B-cnWLxN8L/images/customization/custom-list-2.png?fit=max\&auto=format\&n=y_bUi9B-cnWLxN8L\&q=85\&s=4c8b1d876bb748347bae48707fdf3b3d)

> [!TIP]
>
> Grouped lists: Useful for workflows like issue trackers (e.g., group by
> "Priority" or "Status"), allowing users to quickly refer and insert custom
> entities from your app. With this feature, you can combine multiple entity
> types into one drop down just like Linear.

> [!WARNING]
>
> Make sure the hotkey is a single character such as `#` or `/`.

The items in the list must be in the following schema:

> [!NOTE]
>
> Use `AutocompleteGroup` only for grouped lists. For flat lists, do not include
> `groups` on the config object or `groupId` on items.

```jsx theme={null}
export class AutocompleteGroup {
    id!: string;
    name!: string;
}

export class AutocompleteItem {
    id!: string; // Unique identifier
    name!: string; // Item name. This appears as the main item text in the UI.
    description?: string; // Item description. This appears as the secondary item text in the UI.
    icon?: { url?: string; svg?: string }; // Item icon. Either URL or inline SVG.
    link?: string; // Item link. You can use this to open a link when the item is clicked. Check the event listener below for more details.
    groupId?: string; // Optional: assigns item to a group (by AutocompleteGroup.id)
}
```

##### **Flat List Implementation**

```jsx theme={null}
let customList = [
  {
    id: "1",
    name: "File 1",
    description: "File Description 1",
    icon: { url: "https://cdn-icons-png.flaticon.com/512/9496/9496432.png" },
  },
  {
    id: "2",
    name: "File 2",
    description: "File Description 2",
    icon: { url: "https://cdn-icons-png.flaticon.com/512/11471/11471469.png" },
  },
  {
    id: "3",
    name: "File 3",
    description: "File Description 3",
    icon: { url: "https://cdn-icons-png.flaticon.com/512/2656/2656402.png" },
  },
];

const customListDataOnComment = {
  hotkey: "UNIQUE_HOTKEY", // only single character is allowed. eg: '#'
  type: "custom",
  data: customList, // your customList data here
};
```

> [tab] React / Next.js with Hooks
>
> ```jsx theme={null}
> // Using Props
> <VeltComments customListDataOnComment={customListDataOnComment} />
>
> // Hook
> const commentElement = useCommentUtils();
> commentElement.createCustomListDataOnComment(customListDataOnComment);
>
> ```

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using Props
> <VeltComments customListDataOnComment={customListDataOnComment} />
>
> // Hook
> const commentElement = client.getCommentElement();
> commentElement.createCustomListDataOnComment(customListDataOnComment);
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.createCustomListDataOnComment(customListDataOnComment);
> ```

##### **Grouped List Implementation**

```ts theme={null}
const customListWithGroups = {
  hotkey: "$",
  type: "custom",
  groups: [
    { id: "categories", name: "Categories" },
    { id: "priorities", name: "Priorities" },
  ],
  data: [
    // Categories group
    {
      id: "bug_1",
      name: "Bug 1",
      description: "Bug report 1",
      groupId: "categories",
      icon: { svg: "<svg></svg>" },
    },
    {
      id: "feature_2",
      name: "Feature Request 2",
      description: "New feature 2",
      groupId: "categories",
      icon: { url: "https://random.png" },
    },
    // Priorities group
    {
      id: "high_1",
      name: "High Priority 1",
      description: "Urgent task 1",
      groupId: "priorities",
      icon: { url: "https://random.png" },
    },
    {
      id: "medium_2",
      name: "Medium Priority 2",
      description: "Normal task 2",
      groupId: "priorities",
      icon: { svg: "<svg></svg>" },
    },
    // Ungrouped items
    {
      id: "misc_1",
      name: "Miscellaneous 1",
      description: "Other items 1",
      icon: { url: "https://random.png" },
    },
    {
      id: "note_2",
      name: "Note 2",
      description: "General note 2",
      icon: { svg: "<svg></svg>" },
    },
  ],
};
```

> [tab] React / Next.js with Hooks
>
> ```ts theme={null}
> // Using Props
> <VeltComments customListDataOnComment={customListWithGroups} />
>
> // Hook
> const commentElement = useCommentUtils();
> commentElement.createCustomListDataOnComment(customListWithGroups);
>
> ```

> [tab] React / Next.js
>
> ```ts theme={null}
> const commentElement = client.getCommentElement();
> commentElement.createCustomListDataOnComment(customListWithGroups);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.createCustomListDataOnComment(customListWithGroups);
> ```

##### **Listen to click events on chips**

After the comment is saved, the item will be rendered as a chip on the comment content. When the user clicks on it, you will get an event callback with the data of the clicked chip (`AutocompleteItem`).

> [!NOTE]
>
> This event will also be triggered when the user clicks on the contact chips
> added via the @mentions feature.

> [tab] React / Next.js with Hooks
>
> ```jsx theme={null}
> let autocompleteChipData = useAutocompleteChipClick(); 
> ```

> [tab] React / Next.js
>
> ```jsx theme={null}
> const autocompleteElement = client.getAutocompleteElement();
> const subscription = autocompleteElement.onAutocompleteChipClick().subscribe((_data) => {
>   console.log(_data);
> });
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe()
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const autocompleteElement = Velt.getAutocompleteElement();
> const subscription = autocompleteElement.onAutocompleteChipClick().subscribe((_data) => {
>   console.log(_data);
> });
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe()
> ```

#### customAutocompleteSearch

* Handle autocomplete search for custom list. You should use this if you have a large list that you want to plug into the autocomplete dropdown, and search directly your own data source.
* Event: [`AutocompleteSearchEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#autocompletesearchevent)

> [tab] React / Next.js
>
> **1. Enable the feature**
>
> ```jsx theme={null}
> // Enable via props
> <VeltComments customAutocompleteSearch={true} />
>
> // Or, enable via Comment Element API
> const commentElement = client.getCommentElement();
> commentElement.enableCustomAutocompleteSearch();
> commentElement.disableCustomAutocompleteSearch();
>
> ```
>
> **2. Set initial list**
>
> ```jsx theme={null}
> // For @mentions feature
> contactElement.updateContactList(users);
>
> // For custom list feature
> commentElement.createCustomListDataOnComment({
>     hotkey: "#",
>     type: "custom",
>     data: customListData,
> });
> ```
>
> **3. Handle search event**
>
> ```jsx theme={null}
> commentElement.on('autocompleteSearch').subscribe(async (inputData) => {
>     const searchText = inputData.searchText;
>
>     // For @mentions feature
>     if (inputData.type === 'contact') {
>         const filteredUsersData = await __your_api_call__(searchText);
>         contactElement.updateContactList(filteredUsersData, { merge: false });
>     }
>
>     // For custom list feature
>     if (inputData.type === 'custom') {
>         const filteredListData = await __your_api_call__(searchText, autocompleteData);
>         commentElement.createCustomListDataOnComment({
>             hotkey: "#",
>             type: "custom",
>             data: filteredListData,
>         });
>     }
>
> });
>
> ```

> [tab] Other Frameworks
>
> **1. Enable the feature**
>
> ```js theme={null}
> // Enable via attribute
> <velt-comments custom-autocomplete-search="true"></velt-comments>
>
> // Or, enable via Comment Element API
> const commentElement = Velt.getCommentElement();
> commentElement.enableCustomAutocompleteSearch();
> commentElement.disableCustomAutocompleteSearch();
> ```
>
> **2. Set initial list**
>
> ```js theme={null}
> commentElement.createCustomListDataOnComment({
>     hotkey: "#",
>     type: "custom",
>     data: customListData,
> });
> ```
>
> **3. Handle search event**
>
> ```js theme={null}
> commentElement.on('autocompleteSearch').subscribe(async (inputData) => {
>     const searchText = inputData.searchText;
>
>     if (inputData.type === 'custom') {
>         const filteredListData = await __your_api_call__(searchText, autocompleteData);
>         commentElement.createCustomListDataOnComment({
>             hotkey: "#",
>             type: "custom",
>             data: filteredListData,
>         });
>     }
>
> });
>
> ```

# Event Subscription

### [on](https://velt.dev/docs/api-reference/sdk/api/api-methods.md#on)

Subscribe to Comment Events. Here is the list of events you can subscribe to and the event objects you will receive.

| Category | Event Type | Description | Event Object |
| - | - | - | - |
| Threads | `addCommentAnnotationDraft` | Triggered before `addCommentAnnotation` event clicks on the comment tool and the composer is rendered. | [AddCommentAnnotationDraftEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addcommentannotationdraftevent) |
| Threads | `addCommentAnnotation` | Add a new comment annotation | [AddCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addcommentannotationevent) |
| Threads | `addCommentDraft` | Triggered when a user abandons a reply or edit composer without saving | [AddCommentDraftEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addcommentdraftevent) |
| Threads | `deleteCommentAnnotation` | Delete a comment annotation | [DeleteCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deletecommentannotationevent) |
| Messages | `addComment` | Add a new comment | [AddCommentEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addcommentevent) |
| Messages | `updateComment` | Update an existing comment | [UpdateCommentEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#updatecommentevent) |
| Messages | `deleteComment` | Delete a comment | [DeleteCommentEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deletecommentevent) |
| Messages | `commentActionClicked` | Triggered when a customer-defined action chip on a comment row is clicked | [CommentActionClickedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentactionclickedevent) |
| @Mentions | `assignUser` | Assign a user to a comment | [AssignUserEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#assignuserevent) |
| @Mentions | `subscribeCommentAnnotation` | Subscribe to a comment annotation | [SubscribeCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#subscribecommentannotationevent) |
| @Mentions | `unsubscribeCommentAnnotation` | Unsubscribe from a comment annotation | [UnsubscribeCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#unsubscribecommentannotationevent) |
| @Mentions | `autocompleteSearch` | When user starts searching for a contact in the @mentions dropdown or for a list item in the custom list dropdown | [AutocompleteSearchEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#autocompletesearchevent) |
| Attachments | `addAttachment` | Add an attachment to a comment | [AddAttachmentEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addattachmentevent) |
| Attachments | `deleteAttachment` | Delete an attachment from a comment | [DeleteAttachmentEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deleteattachmentevent) |
| Attachments | `attachmentDownloadClicked` | Triggered when attachment download button is clicked | [AttachmentDownloadClickedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#attachmentdownloadclickedevent) |
| Reactions | `addReaction` | Add a reaction to a comment | [AddReactionEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addreactionevent) |
| Reactions | `deleteReaction` | Delete a reaction from a comment | [DeleteReactionEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deletereactionevent) |
| Reactions | `toggleReaction` | Toggle a reaction on a comment | [ToggleReactionEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#togglereactionevent) |
| Status & Priority | `updateStatus` | Update the status of a comment | [UpdateStatusEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#updatestatusevent) |
| Status & Priority | `resolveComment` | Resolve a comment | [ResolveCommentEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#resolvecommentevent) |
| Status & Priority | `updatePriority` | Update the priority of a comment | [UpdatePriorityEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#updatepriorityevent) |
| Status & Priority | `approveCommentAnnotation` | Approve a comment annotation | [ApproveCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#approvecommentannotationevent) |
| Status & Priority | `acceptCommentAnnotation` | Accept a comment annotation | [AcceptCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#acceptcommentannotationevent) |
| Status & Priority | `rejectCommentAnnotation` | Reject a comment annotation | [RejectCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#rejectcommentannotationevent) |
| Suggestions | `suggestionAccepted` | Triggered when a reviewer accepts a suggestion (agent finding or human-authored) from the comment dialog | [SuggestionAcceptEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#suggestionacceptevent) |
| Suggestions | `suggestionRejected` | Triggered when a reviewer rejects a suggestion (agent finding or human-authored) from the comment dialog | [SuggestionRejectEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#suggestionrejectevent) |
| Recordings | `deleteRecording` | Delete a recording from a comment | [DeleteRecordingEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deleterecordingevent) |
| Deep Links | `copyLink` | Copy a deep link to a comment | [CopyLinkEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#copylinkevent) |
| Comment Sidebar | `commentSidebarDataInit` | Triggered when comment sidebar data is first loaded | [CommentSidebarDataInitEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentsidebardatainitevent) |
| Comment Sidebar | `commentSidebarDataUpdate` | Triggered when comment sidebar data is updated | [CommentSidebarDataUpdateEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentsidebardataupdateevent) |
| Comment Sidebar | `sidebarOpen` | Triggered when the comment sidebar opens | [SidebarOpenEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#sidebaropenevent) |
| Comment Sidebar | `sidebarClose` | Triggered when the comment sidebar closes | [SidebarCloseEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#sidebarcloseevent) |
| Comment Sidebar | `commentClick` | Triggered when a comment is clicked in the sidebar list | [CommentClickEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentclickevent) |
| Comment Sidebar | `commentNavigationButtonClick` | Triggered when the navigation ("go to") button on a sidebar comment is clicked | [CommentNavigationButtonClickEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentnavigationbuttonclickevent) |
| UI | `composerClicked` | Triggered when comment composer is clicked | [ComposerClickedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#composerclickedevent) |
| UI | `composerTextChange` | Triggered when text changes in any comment composer. Includes full draft annotation object and composer ID. | [ComposerTextChangeEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#composertextchangeevent) |
| UI | `commentPinClicked` | Triggered when a comment pin is clicked | [CommentPinClickedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentpinclickedevent) |
| UI | `commentBubbleClicked` | Triggered when a comment bubble is clicked | [CommentBubbleClickedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentbubbleclickedevent) |
| UI | `linkClicked` | Triggered when a clickable link in comment content is clicked | [LinkClickedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#linkclickedevent) |
| UI | `commentToolClicked` | Past-tense alias for `commentToolClick`, identical payload | [CommentToolClickedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commenttoolclickedevent) |
| UI | `sidebarButtonClicked` | Past-tense alias for `sidebarButtonClick`, identical payload | [SidebarButtonClickedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#sidebarbuttonclickedevent) |
| Recorder | `transcriptionDone` | Triggered when a transcription is generated and ready | [TranscriptionDoneEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#transcriptiondoneevent) |
| Threads | `commentSaved` | Triggered when a comment annotation is saved to the database | [CommentSavedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentsavedevent) |
| Threads | `commentSaveTriggered` | Triggered immediately when the save button is clicked, before async save completes | [CommentSaveTriggeredEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentsavetriggeredevent) |
| Visibility | `visibilityOptionClicked` | Triggered when a user selects a visibility option | [VisibilityOptionClickedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#visibilityoptionclickedevent) |

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Hook
> const commentEventCallbackData = useCommentEventCallback('addCommentAnnotation');
> useEffect(() => {
>   if (commentEventCallbackData) {
>     // Handle comment action callback event response
>   }
> }, [commentEventCallbackData]);
>
> // API Method
> const commentElement = client.getCommentElement();
> commentElement.on('addCommentAnnotation').subscribe((event) => {
>     // Handle the event response
> });
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.on('addCommentAnnotation').subscribe((event) => {
>     // Handle the event response
> });
> ```

# Attachments

#### enableAttachments

![](https://mintcdn.com/velt/kAkMSIYF4ZlrlwLm/images/file-attachment.png?fit=max\&auto=format\&n=kAkMSIYF4ZlrlwLm\&q=85\&s=00c2e3bb6c8c5929a950b9d49edb5305)

Whether file attachments are enabled.

Default: `true`

When this is on, users can attach image files to their comments. Users can download or delete an attachment. Users can attach multiple files at once.

Currently we support `.png`, `.jpg`, `.gif` (static & animated), `.svg` file types up to 15MB per file.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments attachments={true} />
> ```
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableAttachments();
> commentElement.disableAttachments();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments attachments="true"></velt-comments>
> ```
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableAttachments();
> commentElement.disableAttachments();
> ```

#### enableAttachmentDownload

Controls whether clicking an attachment triggers a file download.

Default: `true`

When disabled, users can still click attachments but no download is triggered. The `attachmentDownloadClicked` event fires on every attachment click regardless of this setting.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using Component Props
> <VeltComments attachmentDownload={true} />
> ```
>
> ```jsx theme={null}
> // Using API methods
> const commentElement = client.getCommentElement();
> commentElement.enableAttachmentDownload();
> commentElement.disableAttachmentDownload();
> ```
>
> ```jsx theme={null}
> // Listening to the event
> const commentEventCallbackData = useCommentEventCallback('attachmentDownloadClicked');
> useEffect(() => {
>   if (commentEventCallbackData) {
>     // Handle attachment download clicked event
>   }
> }, [commentEventCallbackData]);
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Using HTML attributes -->
> <velt-comments attachment-download="true"></velt-comments>
> ```
>
> ```js theme={null}
> // Using API methods
> const commentElement = Velt.getCommentElement();
> commentElement.enableAttachmentDownload();
> commentElement.disableAttachmentDownload();
> ```
>
> ```js theme={null}
> // Listening to the event
> const commentElement = Velt.getCommentElement();
> commentElement.on('attachmentDownloadClicked').subscribe((event) => {
>   // Handle attachment download clicked event
> });
> ```

#### enableScreenshot

Whether screenshot option is enabled in comments.

Default: `false`

When enabled, users can attach screenshots when adding comments. This provides a quick way to capture and share visual context.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using Component Props
> <VeltComments screenshot={true} />
>
> // Using API methods
> const commentElement = client.getCommentElement();
> commentElement.enableScreenshot();
> commentElement.disableScreenshot();
>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Using HTML attributes -->
> <velt-comments screenshot="true"></velt-comments>
>
> <script>
> // Using API methods
> const commentElement = Velt.getCommentElement();
> commentElement.enableScreenshot();
> commentElement.disableScreenshot();
> </script>
> ```

#### addAttachment

* Add an attachment to a specific comment annotation
* Params: [AddAttachmentRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addattachmentrequest)
* Returns: Promise\<[AddAttachmentResponse\[\]](https://velt.dev/docs/api-reference/sdk/models/data-models#addattachmentresponse)>

> [tab] React / Next.js
>
> ```jsx theme={null}
> const addAttachmentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   files: '<Files[]>'
> };
>
> // Hook
> const { addAttachment } = useAddAttachment();
> const attachmentResponses = await addAttachment(addAttachmentRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const attachmentResponses = await commentElement.addAttachment(addAttachmentRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const addAttachmentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   files: '<Files[]>'
> };
>
> const commentElement = Velt.getCommentElement();
> const attachmentResponses = await commentElement.addAttachment(addAttachmentRequest);
> ```

#### deleteAttachment

* Delete an attachment from a specific comment annotation
* Params: [DeleteAttachmentRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deleteattachmentrequest)
* Returns: Promise\<[DeleteAttachmentEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deleteattachmentevent) | null>

> [tab] React / Next.js
>
> ```jsx theme={null}
> const deleteAttachmentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   commentId: COMMENT_ID,
>   attachmentId: 'ATTACHMENT_ID'
> };
>
> // Hook
> const { deleteAttachment } = useDeleteAttachment();
> const deleteAttachmentEvent = await deleteAttachment(deleteAttachmentRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const deleteAttachmentEvent = await commentElement.deleteAttachment(deleteAttachmentRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const deleteAttachmentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   commentId: COMMENT_ID,
>   attachmentId: 'ATTACHMENT_ID'
> };
>
> const commentElement = Velt.getCommentElement();
> const deleteAttachmentEvent = await commentElement.deleteAttachment(deleteAttachmentRequest);
> ```

#### getAttachment

* Get attachments from a specific comment annotation
* Params: [GetAttachmentRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#getattachmentrequest)
* Returns: Promise\<[Attachment\[\]](https://velt.dev/docs/api-reference/sdk/models/data-models#attachment)>

> [tab] React / Next.js
>
> ```jsx theme={null}
> const getAttachmentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   commentId: COMMENT_ID,
> };
>
> // Hook
> const { getAttachment } = useGetAttachment();
> const attachments = await getAttachment(getAttachmentRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const attachments = await commentElement.getAttachment(getAttachmentRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const getAttachmentRequest = {
>   annotationId: 'ANNOTATION_ID',
>   commentId: COMMENT_ID,
> };
>
> const commentElement = Velt.getCommentElement();
> const attachments = await commentElement.getAttachment(getAttachmentRequest);
> ```

#### allowedFileTypes

Limit file types in comment attachments by specifying allowed file extensions.

Default: Not specified (all supported file types allowed)

When this property is set, users can only attach files with the specified extensions. This helps you maintain security standards and ensure only approved file types are shared in collaborative discussions.

By default, Velt supports `.png`, `.jpg`, `.gif` (static & animated), `.svg` file types up to 15MB per file. With `allowedFileTypes`, you can restrict to a subset of these or any other file extensions your application requires.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using component prop
> <VeltComments allowedFileTypes={['jpg', 'png']} />
> ```
>
> ```jsx theme={null}
> // Using API method
> const commentElement = client.getCommentElement();
> commentElement.setAllowedFileTypes(['jpg', 'png']);
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Using HTML attribute -->
> <velt-comments allowed-file-types="['jpg', 'png']"></velt-comments>
> ```
>
> ```js theme={null}
> // Using API method
> const commentElement = Velt.getCommentElement();
> commentElement.setAllowedFileTypes(['jpg', 'png']);
> ```

#### attachmentNameInMessage

Display the attachment filename in the message when a file is attached.

Default: `false`

When this property is enabled, the attachment filename will appear in the message text when a user selects a file to attach. This provides immediate visual confirmation of which file they've attached to their comment, improving clarity before submitting.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments attachmentNameInMessage={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments attachment-name-in-message="true"></velt-comments>
> ```

#### setComposerFileAttachments

Programmatically add file attachments to the comment composer from your application instead of requiring users to select files from the file system.

This method enables workflows where you want to attach files programmatically, such as:

* Attaching screenshots captured within your application
* Including generated reports or documents
* Adding files from your own storage system
* Pre-populating attachments based on user context

Params: [UploadFileData](https://velt.dev/docs/api-reference/sdk/models/data-models.md#uploadfiledata)

The `UploadFileData` object accepts the following properties:

* `files` (required): Array of File objects to attach to the comment composer
* `annotationId` (optional): ID of the target comment annotation. Use this to add attachments to an existing comment thread
* `targetElementId` (optional): ID of the target element where the comment composer is attached. Use this to add attachments to a specific element

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
>
> // Add attachments to a new comment composer
> commentElement.setComposerFileAttachments({
> files: [file1, file2],
> });
>
> // Add attachments to an existing comment annotation
> commentElement.setComposerFileAttachments({
> files: [file1, file2],
> annotationId: 'annotation-123',
> });
>
> // Add attachments to a comment composer on a specific element
> commentElement.setComposerFileAttachments({
> files: [file1, file2],
> targetElementId: 'element-456',
> });
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
>
> // Add attachments to a new comment composer
> commentElement.setComposerFileAttachments({
>   files: [file1, file2],
> });
>
> // Add attachments to an existing comment annotation
> commentElement.setComposerFileAttachments({
>   files: [file1, file2],
>   annotationId: 'annotation-123',
> });
>
> // Add attachments to a comment composer on a specific element
> commentElement.setComposerFileAttachments({
>   files: [file1, file2],
>   targetElementId: 'element-456',
> });
> ```

#### attachmentDownload

Control whether attachment downloads happen automatically when users click the download button.

Default: `true`

When enabled, clicking the download button on an attachment will automatically download the file. When disabled, the automatic download is prevented, and you can handle the download action with custom logic by subscribing to the `attachmentDownloadClicked` event.

This is useful for:

* Tracking download analytics before initiating the download
* Implementing custom download URLs or CDN routes
* Adding access control checks before allowing downloads

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using component prop
> <VeltComments attachmentDownload={false} />
> ```
>
> ```jsx theme={null}
> // Using API methods
> const commentElement = client.getCommentElement();
> commentElement.enableAttachmentDownload();
> commentElement.disableAttachmentDownload();
> ```
>
> ```jsx theme={null}
> // Subscribe to download click events
> const commentElement = client.getCommentElement();
> commentElement.on('attachmentDownloadClicked').subscribe((event) => {
>   // event.annotationId - ID of the comment annotation
>   // event.commentAnnotation - Full comment annotation object
>   // event.attachment - The attachment that was clicked
>   // event.metadata - Event metadata
>
> // Implement custom download logic
> console.log('Attachment download clicked:', event.attachment);
>
> // Example: Custom analytics tracking
> trackDownload(event.attachment.id);
>
> // Example: Custom download URL
> window.open(event.attachment.url, '\_blank');
> });
>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Using HTML attribute -->
> <velt-comments attachment-download="false"></velt-comments>
> ```
>
> ```js theme={null}
> // Using API methods
> const commentElement = Velt.getCommentElement();
> commentElement.enableAttachmentDownload();
> commentElement.disableAttachmentDownload();
> ```
>
> ```js theme={null}
> // Subscribe to download click events
> const commentElement = Velt.getCommentElement();
> commentElement.on("attachmentDownloadClicked").subscribe((event) => {
>   // event.annotationId - ID of the comment annotation
>   // event.commentAnnotation - Full comment annotation object
>   // event.attachment - The attachment that was clicked
>   // event.metadata - Event metadata
>
>   // Implement custom download logic
>   console.log("Attachment download clicked:", event.attachment);
>
>   // Example: Custom analytics tracking
>   trackDownload(event.attachment.id);
>
>   // Example: Custom download URL
>   window.open(event.attachment.url, "_blank");
> });
> ```

# Text Formatting

#### enableFormatOptions

Enable rich text formatting toolbar in comment composers. Users can apply bold, italic, underline, and strikethrough formatting.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using Component Props
> <VeltComments formatOptions={true} />
>
> // Using API methods
> const commentElement = client.getCommentElement();
> commentElement.enableFormatOptions();
> commentElement.disableFormatOptions();
>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Using HTML attributes -->
> <velt-comments format-options="true"></velt-comments>
>
> <script>
> // Using API methods
> const commentElement = Velt.getCommentElement();
> commentElement.enableFormatOptions();
> commentElement.disableFormatOptions();
> </script>
> ```

#### setFormatConfig

Configure which format types are available in the formatting toolbar.

Params: [`FormatConfig`](https://velt.dev/docs/api-reference/sdk/models/data-models#formatconfig)

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using Hooks
> const commentElement = useCommentUtils();
> commentElement.setFormatConfig({
>   bold: { enable: true },
>   italic: { enable: true },
>   underline: { enable: false },
>   strikethrough: { enable: false }
> });
>
> // Using API methods
> const commentElement = client.getCommentElement();
> commentElement.setFormatConfig({
> bold: { enable: true },
> italic: { enable: true },
> underline: { enable: false },
> strikethrough: { enable: false }
> });
>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <script>
> const commentElement = Velt.getCommentElement();
> commentElement.setFormatConfig({
>   bold: { enable: true },
>   italic: { enable: true },
>   underline: { enable: false },
>   strikethrough: { enable: false }
> });
> </script>
> ```

# Reactions

#### enableReactions

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/reactions.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=b6722120add1099a4b8663de34f4cfa1)

Whether emoji reactions are enabled.

Default: `true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments reactions={true} />
> ```
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableReactions();
> commentElement.disableReactions();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments reactions="true"></velt-comments>
> ```
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableReactions();
> commentElement.disableReactions();
> ```

#### setCustomReactions

* You can set custom reactions by passing a map that contains information about the reactions you want to add.
* The map keys should be the reaction ID, and the map value should contain an object with either an `url` or `emoji` field to represent the reaction icon you want to use.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
>
> const customReactions = {
>   reactionId1: {
>     emoji: "🤣", // This will default to system emoji
>   },
>   reactionId2: {
>     emoji: "🎉", // This will default to system emoji
>   },
>   reactionId3: {
>     emoji: "🚀", // This will default to system emoji
>   },
> };
> commentElement.setCustomReactions(customReactions);
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
>
> const customReactions = {
> "reactionId1": {
> "emoji": "🤣" // This will default to system emoji
> },
> "reactionId2": {
> "emoji": "🎉" // This will default to system emoji
> },
> "reactionId3": {
> "emoji": "🚀" // This will default to system emoji
> }
> }
> commentElement.setCustomReactions(customReactions);
>
> ```

#### addReaction

* Add a reaction to a specific comment annotation
* Params: [AddReactionRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addreactionrequest)
* Returns: Promise\<[AddReactionEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#addreactionevent) | null>

> [tab] React / Next.js
>
> ```jsx theme={null}
> const addReactionRequest = {
>   annotationId: '-OCWolieeXVOfPqTa0G-',
>   commentId: 384399,
>   reaction: {
>     reactionId: 'fire',
>     customReaction: {
>           "emoji": "🔥"
>     }
>   }
> };
>
> // Hook
> const { addReaction } = useAddReaction();
> const addReactionEvent = await addReaction(addReactionRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const addReactionEvent = await commentElement.addReaction(addReactionRequest);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const addReactionRequest = {
>   annotationId: '-OCWolieeXVOfPqTa0G-',
>   commentId: 384399,
>   reaction: {
>     reactionId: 'fire',
>     customReaction: {
>           "emoji": "🔥"
>     }
>   }
> };
>
> const commentElement = Velt.getCommentElement();
> const addReactionEvent = await commentElement.addReaction(addReactionRequest);
>
> ```

#### deleteReaction

* Delete a reaction from a specific comment annotation
* Params: [DeleteReactionRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deletereactionrequest)
* Returns: Promise\<[DeleteReactionEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deletereactionevent) | null>

> [tab] React / Next.js
>
> ```jsx theme={null}
> const deleteReactionRequest = {
>   annotationId: '-OCWolieeXVOfPqTa0G-',
>   commentId: 384399,
>   reaction: {
>     reactionId: 'fire'
>   }
> };
>
> // Hook
> const { deleteReaction } = useDeleteReaction();
> const deleteReactionEvent = await deleteReaction(deleteReactionRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const deleteReactionEvent = await commentElement.deleteReaction(deleteReactionRequest);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const deleteReactionRequest = {
>   annotationId: '-OCWolieeXVOfPqTa0G-',
>   commentId: 384399,
>   reaction: {
>     reactionId: 'fire'
>   }
> };
>
> const commentElement = Velt.getCommentElement();
> const deleteReactionEvent = await commentElement.deleteReaction(deleteReactionRequest);
>
> ```

#### toggleReaction

* Toggle a reaction for a specific comment annotation
* Params: [ToggleReactionRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#togglereactionrequest)
* Returns: Promise\<[ToggleReactionEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#togglereactionevent) | null>

> [tab] React / Next.js
>
> ```jsx theme={null}
> const toggleReactionRequest = {
>   annotationId: '-OCWolieeXVOfPqTa0G-',
>   commentId: 384399,
>   reaction: {
>     reactionId: 'fire'
>   }
> };
>
> // Hook
> const { toggleReaction } = useToggleReaction();
> const toggleReactionEvent = await toggleReaction(toggleReactionRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const toggleReactionEvent = await commentElement.toggleReaction(toggleReactionRequest);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const toggleReactionRequest = {
>   annotationId: '-OCWolieeXVOfPqTa0G-',
>   commentId: 384399,
>   reaction: {
>     reactionId: 'fire'
>   }
> };
>
> const commentElement = Velt.getCommentElement();
> const toggleReactionEvent = await commentElement.toggleReaction(toggleReactionRequest);
>
> ```

# Status & Priority

#### enableStatus

![](https://mintcdn.com/velt/gY7ilEx2g4g3-HVe/images/status-default.png?fit=max\&auto=format\&n=gY7ilEx2g4g3-HVe\&q=85\&s=d2b5d1dbc07f584abdb0f1f18408f52c)

Whether to enable the default status dropdown & filters.

`Default: true`

When this is on, users can assign a status to each comment & filter comment by status in the sidebar. You can customize the list of status options as shown below on this page.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments status={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments status="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableStatus();
> commentElement.disableStatus();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableStatus();
> commentElement.disableStatus();
> ```

#### setCustomStatus

![](https://mintcdn.com/velt/2O8vk8YlVD4Kq-ni/images/custom-status.png?fit=max\&auto=format\&n=2O8vk8YlVD4Kq-ni\&q=85\&s=ebf2ba52820edf0037c3975d1ec7d7b5)

* With custom statuses, you can replace the default statuses with your own values.
* These statuses are also used in the comment sidebar to filter comments by status.
* There are three types of statuses:
  * `default`: This will be the default status assigned to each comment.
  * `ongoing`: This is treated as an intermediary status, you can add as many statuses with type ongoing as you want.
  * `terminal`: This represents a status that is completed. Comments with this status type are no longer shown in the DOM.
* Ensure that there are at least 2 statuses set.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.setCustomStatus([
>   {
>     id: 'open',
>     name: 'Open',
>     color: '#625df5',
>     lightColor: '#f2f2fe',
>     type: 'default',
>   },
>   {
>     id: 'resolved',
>     name: 'Resolved',
>     color: '#198f65',
>     lightColor: '#edf6f3',
>     type: 'terminal',
>   },
> ])
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setCustomStatus([
>   {
>     id: 'open',
>     name: 'Open',
>     color: '#625df5',
>     lightColor: '#f2f2fe',
>     type: 'default',
>   },
>   {
>     id: 'resolved',
>     name: 'Resolved',
>     color: '#198f65',
>     lightColor: '#edf6f3',
>     type: 'terminal',
>   },
> ])
> ```

#### enableResolveButton

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/resolve-button.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=b9a34780cbc2230ce217a6be496d5908)

Whether to show resolve button on comments.

`Default: true`

This adds a tick mark button on the top right corner of the comment dialog. Clicking on this button will mark the comment as resolved.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments resolveButton={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments resolve-button="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableResolveButton();
> commentElement.disableResolveButton();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableResolveButton();
> commentElement.disableResolveButton();
> ```

#### updateStatus

* Updates the status of a comment annotation.
* Params: [UpdateStatusRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#updatestatusrequest)
* Returns: [UpdateStatusEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#updatestatusevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const updateStatusRequest = {
>   annotationId: 'ANNOTATION_ID',
>   status: {
>     "id": "open",
>     "name": "Open",
>     "color": "white",
>     "lightColor":"green",
>     "type": "default"
>   }
> };
>
> // Hook
> const { updateStatus } = useUpdateStatus();
> const updateStatusEvent = await updateStatus(updateStatusRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const updateStatusEvent = await commentElement.updateStatus(updateStatusRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const updateStatusRequest = {
>   annotationId: 'ANNOTATION_ID',
>   status: {
>     "id": "open",
>     "name": "Open",
>     "color": "white",
>     "lightColor":"green",
>     "type": "default"
>   }
> };
>
> const commentElement = Velt.getCommentElement();
> const updateStatusEvent = await commentElement.updateStatus(updateStatusRequest);
> ```

#### resolveCommentAnnotation

* Resolves a comment annotation
* Params: [ResolveCommentAnnotationRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#resolvecommentannotationrequest)
* Returns: [ResolveCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#resolvecommentannotationevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const resolveCommentAnnotationRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> // Hook
> const { resolveCommentAnnotation } = useResolveCommentAnnotation();
> const resolveCommentAnnotationEvent = await resolveCommentAnnotation(resolveCommentAnnotationRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const resolveCommentAnnotationEvent = await commentElement.resolveCommentAnnotation(resolveCommentAnnotationRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const resolveCommentAnnotationRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> const commentElement = Velt.getCommentElement();
> const resolveCommentAnnotationEvent = await commentElement.resolveCommentAnnotation(resolveCommentAnnotationRequest);
> ```

#### enablePriority

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/priority-default.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=cae4c4a67116529da6779d6a9382eb2b)

Whether to enable setting priority on comments.

`Default: false`

When this is on, users can assign a priority to each comment & filter comment by priority in the sidebar. You can customize the list of priority options as shown later on this page in the Set Custom Priorities section.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments priority={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments priority="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enablePriority();
> commentElement.disablePriority();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enablePriority();
> commentElement.disablePriority();
> ```

#### setCustomPriority

![](https://mintcdn.com/velt/2O8vk8YlVD4Kq-ni/images/custom-priority.png?fit=max\&auto=format\&n=2O8vk8YlVD4Kq-ni\&q=85\&s=d2ed3a5ceeca1c57de076098187bfe2c)

> [tab] React / Next.js
>
> Pass custom priorities in the `customPriority` prop.
>
> `Default priorities: P0, P1, P2`
>
> With custom priorities, you can replace the default priorities with your own values. These priorities are also used in the comment sidebar to filter comments by priority.
>
> This will work if you have enabled the priority feature.
>
> The `color` property is used to set the priority pill background color.
>
> The `lightColor` property sets the background color of the filter.
>
> ```js theme={null}
> <VeltComments
>   customPriority={[
>     {
>       id: "low",
>       name: "Low",
>       color: "red",
>       lightColor: "pink",
>     },
>   ]}
> />
> ```

> [tab] Other Frameworks
>
> Pass custom priorities in the `custom-priority`.
>
> `Default priorities: P0, P1, P2`
>
> With custom priorities, you can replace the default priorities with your own values. These priorities are also used in the comment sidebar to filter comments by priority.
>
> This will work if you have enabled the priority feature.
>
> The `color` property is used to set the priority pill background color.
>
> The `lightColor` property sets the background color of the filter.
>
> ```js theme={null}
> <velt-comments
>   custom-priority='[
>   {
>     "id": "low",
>     "name": "Low",
>     "color": "red",
>     "lightColor": "pink",
>   }
> ]'
> ></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.setCustomPriority([
>   {
>     "id": "low",
>     "name": "Low",
>     "color": "red",
>     "lightColor": "pink",
>   },
> ])
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setCustomPriority([
>   {
>     "id": "low",
>     "name": "Low",
>     "color": "red",
>     "lightColor": "pink",
>   },
> ])
> ```

> [!WARNING]
>
> Make sure to have at least 2 categories set.

#### updatePriority

* Updates the priority of a comment annotation
* Params: [UpdatePriorityRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#updatepriorityrequest)
* Returns: [UpdatePriorityEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#updatepriorityevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const updatePriorityRequest = {
>   annotationId: 'ANNOTATION_ID',
>   priority: {
>     "id": "low",
>     "name": "Low",
>     "color": "red",
>     "lightColor": "pink",
>   }
> };
>
> // Hook
> const { updatePriority } = useUpdatePriority();
> const updatePriorityEvent = await updatePriority(updatePriorityRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const updatePriorityEvent = await commentElement.updatePriority(updatePriorityRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const updatePriorityRequest = {
>   annotationId: 'ANNOTATION_ID',
>   priority: {
>     "id": "low",
>     "name": "Low",
>     "color": "red",
>     "lightColor": "pink",
>   }
> };
>
> const commentElement = Velt.getCommentElement();
> const updatePriorityEvent = await commentElement.updatePriority(updatePriorityRequest);
> ```

# Recording

#### deleteRecording

* Delete a recording from a specific comment annotation
* Params: [DeleteRecordingRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deleterecordingrequest)
* Returns: Promise\<[DeleteRecordingEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#deleterecordingevent) | null>

> [tab] React / Next.js
>
> ```jsx theme={null}
> const deleteRecordingRequest = {
>   annotationId: 'ANNOTATION_ID',
>   commentId: COMMENT_ID,
>   recordingId: 'RECORDING_ID'
> };
>
> // Hook
> const { deleteRecording } = useDeleteRecording();
> const deleteRecordingEvent = await deleteRecording(deleteRecordingRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const deleteRecordingEvent = await commentElement.deleteRecording(deleteRecordingRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const deleteRecordingRequest = {
>   annotationId: 'ANNOTATION_ID',
>   commentId: COMMENT_ID,
>   recordingId: 'RECORDING_ID'
> };
>
> const commentElement = Velt.getCommentElement();
> const deleteRecordingEvent = await commentElement.deleteRecording(deleteRecordingRequest);
> ```

#### getRecording

* Get recordings from a specific comment annotation
* Params: [GetRecordingRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#getrecordingrequest)
* Returns: Promise\<[RecordedData\[\]](https://velt.dev/docs/api-reference/sdk/models/data-models#recordeddata)>

> [tab] React / Next.js
>
> ```jsx theme={null}
> const getRecordingRequest = {
>   annotationId: 'ANNOTATION_ID',
>   commentId: COMMENT_ID
> };
>
> // Hook
> const { getRecording } = useGetRecording();
> const recordings = await getRecording(getRecordingRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const recordings = await commentElement.getRecording(getRecordingRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const getRecordingRequest = {
>   annotationId: 'ANNOTATION_ID',
>   commentId: COMMENT_ID
> };
>
> const commentElement = Velt.getCommentElement();
> const recordings = await commentElement.getRecording(getRecordingRequest);
> ```

#### setAllowedRecordings

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/recorder.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=19dc5bb17927fa6c802f26d1777694d9)

Set the Recorder media options within Comments: (`audio`, `screen`, `video`, `all`).

* `audio`: enables audio recording
* `screen`: enables screen recording
* `video`: enables video recording
* `all`: enables all recording options
* `none`: disables all recording options

Default: `"audio"`

> [!TIP]
>
> **Disabling video recording in comments:** pass any combination that omits `video` (for example `"audio"`, `"screen"`, or `"audio,screen"`). To turn the Recorder off entirely in comments, use `"none"`.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments recordings="video,screen" />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.setAllowedRecordings("video"); // set video mode only
> commentElement.setAllowedRecordings("audio,screen"); // set audio and screen mode only
> commentElement.setAllowedRecordings("all"); // set all modes
> commentElement.setAllowedRecordings("none"); // disable all modes
> ```

**Using Props:**

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments recordings="video,screen"></velt-comments>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setAllowedRecordings("video"); // set video mode only
> commentElement.setAllowedRecordings("audio,screen"); // set audio and screen mode only
> commentElement.setAllowedRecordings("all"); // set all modes
> commentElement.setAllowedRecordings("none"); // disable all modes
> ```

#### enableRecordingCountdown

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/recording-countdown.gif?s=afe80f49d30b287196175210d8a9f275)

Whether the Recorder countdown is enabled.

Default: `true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments recordingCountdown={false} />
> ```
>
> ```jsx theme={null}
> const recorderElement = client.getRecorderElement();
> recorderElement.enableRecordingCountdown();
> recorderElement.disableRecordingCountdown();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments recording-countdown="false"></velt-comments>
> ```
>
> ```jsx theme={null}
> const recorderElement = Velt.getRecorderElement();
> recorderElement.enableRecordingCountdown();
> recorderElement.disableRecordingCountdown();
> ```

#### enableRecordingTranscription

Controls whether to enable AI transcription for recordings.

Default: `enabled`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments recordingTranscription={false} />
> ```
>
> **Using API Methods:**
>
> ```javascript theme={null}
> // Using comment element
> const commentElement = client.getCommentElement();
> commentElement.enableRecordingTranscription();
> commentElement.disableRecordingTranscription();
>
> // Or using recorder element
> const recorderElement = client.getRecorderElement();
> recorderElement.enableRecordingTranscription();
> recorderElement.disableRecordingTranscription();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments recording-transcription="false"></velt-comments>
> ```
>
> **Using API Methods:**
>
> ```javascript theme={null}
> // Using comment element
> const commentElement = Velt.getCommentElement();
> commentElement.enableRecordingTranscription();
> commentElement.disableRecordingTranscription();
>
> // Or using recorder element
> const recorderElement = Velt.getRecorderElement();
> recorderElement.enableRecordingTranscription();
> recorderElement.disableRecordingTranscription();
> ```

# Deep Link

#### getLink

* Get a link to a specific comment annotation
* Params: [GetLinkRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#getlinkrequest)
* Returns: [GetLinkResponse](https://velt.dev/docs/api-reference/sdk/models/data-models.md#getlinkresponse)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const getLinkRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> // Hook
> const { getLink } = useGetLink();
> const getLinkResponse = await getLink(getLinkRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const getLinkResponse = await commentElement.getLink(getLinkRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const getLinkRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> const commentElement = Velt.getCommentElement();
> const getLinkResponse = await commentElement.getLink(getLinkRequest);
> ```

#### copyLink

* Copy a link to a specific comment annotation to clipboard
* Params: [CopyLinkRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#copylinkrequest)
* Returns: [CopyLinkEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#copylinkevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const copyLinkRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> // Hook
> const { copyLink } = useCopyLink();
> const copyLinkEvent = await copyLink(copyLinkRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const copyLinkEvent = await commentElement.copyLink(copyLinkRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const copyLinkRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> const commentElement = Velt.getCommentElement();
> const copyLinkEvent = await commentElement.copyLink(copyLinkRequest);
> ```

# Navigation

#### scrollToCommentByAnnotationId

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/scroll-on-click.gif?s=a495b786a84e9d17ad543b46a44d7487)

* This will scroll the page to the element directly. This will work if the element is present on the DOM.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.scrollToCommentByAnnotationId("annotationId");
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.scrollToCommentByAnnotationId('annotationId');
> ```

#### selectCommentByAnnotationId

* Use this to programmatically select a comment annotation by its ID.
* When called without arguments or with an invalid ID, it will close the currently selected annotation.
* Example: If the user opens a comment URL from an email notification, you can use this to open the comment dialog after your page has finished rendering.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using Hooks
> const commentElement = useCommentUtils();
>
> // Open a specific annotation
> commentElement.selectCommentByAnnotationId("COMMENT_ANNOTATION_ID");
>
> // Close the currently selected annotation
> commentElement.selectCommentByAnnotationId();
> commentElement.selectCommentByAnnotationId("invalid-id");
>
> // Using API methods
> const commentElement = client.getCommentElement();
>
> // Open a specific annotation
> commentElement.selectCommentByAnnotationId("COMMENT_ANNOTATION_ID");
>
> // Close the currently selected annotation
> commentElement.selectCommentByAnnotationId();
> commentElement.selectCommentByAnnotationId("invalid-id");
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
>
> // Open a specific annotation
> commentElement.selectCommentByAnnotationId('COMMENT_ANNOTATION_ID');
>
> // Close the currently selected annotation
> commentElement.selectCommentByAnnotationId();
> commentElement.selectCommentByAnnotationId('invalid-id');
>
> ```

#### onCommentSelectionChange

> [tab] React / Next.js with Hooks
>
> The `useCommentSelectionChangeHandler` hook can be used to subscribe to Comment selection changes.
>
> ```jsx theme={null}
> import React, { useEffect } from 'react';
> import { useCommentSelectionChangeHandler } from '@veltdev/react';
>
> function YourComponent() {
>     const commentSelectionChange = useCommentSelectionChangeHandler();
>
>     useEffect(() => {
>         console.log('commentSelectionChange', commentSelectionChange);
>     }, [commentSelectionChange]);
>
>     return (
>         <>
>             Selected Comment: {commentSelectionChange.annotation.id}
>         </>
>     );
> }
> ```

> [tab] React / Next.js
>
> The `onCommentSelectionChange()` method can be used to listen Comment selection changes.
>
> ````jsx theme={null}
> const onCommentSelectionChange = (data) => {
>   console.log('onCommentSelectionChange', data);
> }
>
> <VeltComments
>   onCommentSelectionChange={(data) => onCommentSelectionChange(data)}
> />
> ``` Callback response schema:
>
> ```jsx
> export class CommentSelectionChangeData {
>   selected!: boolean;
>   annotation!: CommentAnnotation;
> }
> ````
>
> **API Methods:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> let subscription = commentElement
>   .onCommentSelectionChange()
>   .subscribe((data) => {
>     console.log("onCommentSelectionChange: ", data);
>   });
> ```
>
> **To unsubscribe from the subscription:**
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

> [tab] Other Frameworks
>
> The `onCommentSelectionChange()` method can be used to listen Comment selection changes.
>
> ```jsx theme={null}
> <velt-comments></velt-comments>
> <script>
> const commentTag = document.querySelector('velt-comments');
> commentTag.addEventListener('onCommentSelectionChange', (event) => {
> 	console.log('onCommentSelectionChange event', event.detail);
> });
> </script>
> ```
>
> **Callback response schema:**
>
> ```jsx theme={null}
> export class CommentSelectionChangeData {
>   selected!: boolean;
>   annotation!: CommentAnnotation;
> }
> ```
>
> **API Methods:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> let subscription = commentElement
>   .onCommentSelectionChange()
>   .subscribe((data) => {
>     console.log("onCommentSelectionChange: ", data);
>   });
> ```
>
> **To unsubscribe from the subscription:**
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

#### enableScrollToComment

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/scroll-on-click.gif?s=a495b786a84e9d17ad543b46a44d7487)

Whether, users will be scrolled to the location of a `Comment` when it is clicked.

`Default: true`

By default, users will be redirected to a `Comment` if the comment id is provided in the url. But sometimes this experience is annoying, so we have provided a way to disable the option to automatically scroll users to the location of the `Comment`.

> [tab] React / Next.js
>
> To disable the feature, set `scrollToComment` to `false`.
>
> ```html theme={null}
> <VeltComments scrollToComment={false}/>
> ```

> [tab] Other Frameworks
>
> To disable the feature, set `scroll-to-comment` to `false`.
>
> ```html theme={null}
> <velt-comments scroll-to-comment="false"></velt-comments>
> ```

API methods:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> // To enable scroll to component
> commentElement.enableScrollToComment();
> // To disable scroll to component
> commentElement.disablescrollToComment();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> // To enable scroll to component
> commentElement.enableScrollToComment();
> // To disable scroll to component
> commentElement.disablescrollToComment();
> ```

#### enableIdScopedAnchoring

Whether comment pins rooted at an element id are placed only inside that element.

`Default: false`

When enabled, a comment added on an element with an id shows only if that element is present. The SDK does not look for alternative matches. The comment is hidden if the id is missing, duplicated, or hidden.

Use this for surveys, multi-question pages, and cards that re-render.

By default it applies to every document. On a page with several documents, pass `documentIds` to limit it to those documents (the ids you pass to `setDocuments`). Pins in other documents keep the default placement.

* Params: `config?:` [IdScopedAnchoringConfig](https://velt.dev/docs/api-reference/sdk/models/data-models.md#idscopedanchoringconfig)
  * `documentIds?: string[]`: Document ids to apply it to. Omit for every document. Use `[]` for none.
* Returns: `void`

Each call replaces the previous document list. `disableIdScopedAnchoring()` restores the default placement.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Prop
> <VeltComments idScopedAnchoring={true} />
> <VeltComments idScopedAnchoring={{ documentIds: ['doc-a', 'doc-b'] }} />
>
> // API Method
> const commentElement = client.getCommentElement();
> commentElement.enableIdScopedAnchoring();
> commentElement.enableIdScopedAnchoring({ documentIds: ['doc-a', 'doc-b'] });
> commentElement.disableIdScopedAnchoring();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments id-scoped-anchoring="true"></velt-comments>
> <velt-comments id-scoped-anchoring='{"documentIds":["doc-a","doc-b"]}'></velt-comments>
> ```
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableIdScopedAnchoring();
> commentElement.enableIdScopedAnchoring({ documentIds: ['doc-a', 'doc-b'] });
> commentElement.disableIdScopedAnchoring();
> ```

# DOM Controls

#### allowedElementIds

#### allowedElementClassNames

#### allowedElementQuerySelectors

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/comment-area.gif?s=d7da9f6110476805cd9c0addee8ffeee)

Provide a list of element DOM IDs, class names, or query selectors where commenting should be allowed.

Comments will be disabled for all other elements. Note, this does not impact `Popover` mode.

> [tab] React / Next.js
>
> **Using Props:**
>
> ```js theme={null}
> <VeltComments 
>   allowedElementIds={['some-element']} 
>   allowedElementClassNames={["class-name-1", "class-name-2"]}
>   allowedElementQuerySelectors={["#id1.class-name-1"]}
> />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.allowedElementIds(["some-element"]);
> commentElement.allowedElementClassNames(["class-name-1", "class-name-2"]);
> commentElement.allowedElementQuerySelectors(["#id1.class-name-1"]);
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments 
>   allowed-element-ids='["some-element"]'
>   allowed-element-class-names='["class-name-1", "class-name-2"]'
>   allowed-element-query-selectors='["#id1.class-name-1"]'
> >
>
> </velt-comments>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.allowedElementIds(["some-element"]);
> commentElement.allowedElementClassNames(["class-name-1", "class-name-2"]);
> commentElement.allowedElementQuerySelectors(["#id1.class-name-1"]);
> ```

#### data-velt-comment-disabled

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/comment-area.gif?s=d7da9f6110476805cd9c0addee8ffeee)

Disable certain elements from being commented on.

Add the `data-velt-comment-disabled` attribute to elements where you want to disable commenting.

```html theme={null}
<div data-velt-comment-disabled></div>
```

#### sourceId

* When you have multiple elements with the same DOM ID, you can use the `sourceId` attribute to control which element displays the comment dialog when adding a new comment.
* By default, comments appear on all matching elements.
* This is useful in cases where you have multiple instances of the same data component on a page and want the comment to appear on each instance, such as Popover comments on a table.
* You can randomly generate the `sourceId`. It just needs to be unique for each element in the current session.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentTool sourceId="sourceId1" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comment-tool source-id="sourceId1"></velt-comment-tool>
> ```

# AI Categorization

#### enableAutoCategorize

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/images/ai-categories.png?fit=max\&auto=format\&n=gAz_vLsG-ukKamYM\&q=85\&s=e05f5f3d9a6ab3c9b650e6d5d4da0944)

Whether AI auto-categorization of comments is enabled.

`Default: false`

We use AI to analyze your comment content and auto-categorize it so users can filter comments easily. You can provide a list of custom categories that we should use to categorize the comments (shown below).

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments autoCategorize={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments auto-categorize="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableAutoCategorize();
> commentElement.disableAutoCategorize();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableAutoCategorize();
> commentElement.disableAutoCategorize();
> ```

#### setCustomCategory

![](https://mintcdn.com/velt/2O8vk8YlVD4Kq-ni/images/custom-categories.png?fit=max\&auto=format\&n=2O8vk8YlVD4Kq-ni\&q=85\&s=e893ecf769a2264a46e8a8f15662e1ca)

> [tab] React / Next.js
>
> Pass custom categories in the `customCategory` prop.
>
> `Default categories: Question, Feedback, Bug, Other.`
>
> With custom categories, you can replace the default categories with your own values.
>
> These categories are used in the `Comments Sidebar` to filter comments by category. The AI `autoCategorize` feature uses the list of categories to determine the closest category to choose from.
>
> The input format to the `customCategory` prop should be an array of objects with an `id`, `name`, and `color`.
>
> The `color` property is used to set the category pill background color.
>
> ```js theme={null}
> <VeltComments
>   customCategory={[
>     {
>       id: "bug",
>       name: "Bug",
>       color: "red",
>     },
>   ]}
> />
> ```

> [tab] Other Frameworks
>
> Pass custom categories in the `custom-category`.
>
> `Default categories: Question, Feedback, Bug, Other.`
>
> With custom categories, you can replace the default categories with your own values.
>
> These categories are used in the `Comments Sidebar` to filter comments by category. The AI `auto-categorize` uses the list of categories to determine the closest category to choose from.
>
> The input format to the `custom-category` should be an array of objects with an `id`, `name`, and `color`.
>
> The `color` property is used to set the category pill background color.
>
> ```js theme={null}
> <velt-comments
>   customCategory='[
>   {
>     "id": "bug",
>     "name": "Bug",
>     "color": "red"
>   }
> ]'
> ></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.setCustomCategory([
>   {
>     "id": "bug",
>     "name": "Bug",
>     "color": "red"
>   }
> ])
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setCustomCategory([
>   {
>     id: "bug",
>     name: "Bug",
>     color: "red",
>   },
> ]);
> ```

> [!WARNING]
>
> Make sure to have at least 2 categories set.

# Agent Comments

Agent comments let your AI agents leave comments and findings directly in Velt by calling the Comment Annotations REST APIs. No SDK changes required. They are built on top of the same Comments feature, but render with a special UI: each agent finding is a suggestion with **Accept** and **Reject** buttons on the comment dialog.

For the full guide — the `agent` block, request/response shapes, and `velt` vs `external` agents — see [Agent Comments](https://velt.dev/docs/ai/agent-comments.md).

### Create an agent comment

Your agent calls the [Add Comment Annotations API](https://velt.dev/docs/api-reference/rest-apis/v2/comments-feature/comment-annotations/add-comment-annotations.md) with an `agent` block attached to the root comment and `type: "suggestion"`. The server stamps `sourceType: "agent"` on both the comment and the annotation.

```bash cURL theme={null}
curl -X POST 'https://api.velt.dev/v2/commentannotations/add' \
  -H 'x-velt-api-key: YOUR_API_KEY' \
  -H 'x-velt-auth-token: YOUR_AUTH_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "data": {
      "organizationId": "acme-corp",
      "documentId": "design-mockup-v2",
      "commentAnnotations": [
        {
          "type": "suggestion",
          "commentData": [
            {
              "commentText": "This button has insufficient color contrast.",
              "from": { "userId": "a11y-bot" },
              "agent": {
                "agentSource": "external",
                "agentName": "Accessibility Bot",
                "agentId": "a11y-bot",
                "reason": {
                  "title": "Low color contrast",
                  "description": "Contrast ratio is 2.1:1, below the 4.5:1 WCAG AA threshold.",
                  "severity": "high",
                  "findingType": "pin"
                }
              }
            }
          ]
        }
      ]
    }
  }'
```

To read agent comments back, use the [Get Comment Annotations API](https://velt.dev/docs/api-reference/rest-apis/v2/comments-feature/comment-annotations/get-comment-annotations-v2.md) with agent-specific filters (`agentId`, `executionId`, `agentSource`, `agentSuggestions`, `agentComments`).

### Handle accept / reject

Because agent findings render with **Accept** and **Reject** buttons on the comment dialog, the outcome is emitted on the comment element as the `suggestionAccepted` and `suggestionRejected` events. Subscribe to them to apply the change to your own data or trigger follow-up logic.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const accepted = useCommentEventCallback('suggestionAccepted');
> const rejected = useCommentEventCallback('suggestionRejected');
>
> useEffect(() => {
>   if (accepted) {
>     // accepted.commentAnnotation contains the agent finding
>   }
> }, [accepted]);
>
> useEffect(() => {
>   if (rejected) {
>     // rejected.rejectReason contains the optional reason
>   }
> }, [rejected]);
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
>
> commentElement.on('suggestionAccepted').subscribe(({ commentAnnotation }) => {
>   // commentAnnotation contains the agent finding
> });
>
> commentElement.on('suggestionRejected').subscribe(({ commentAnnotation, rejectReason }) => {
>   // rejectReason contains the optional reason
> });
> ```

# Progress

Turn a comment into a live progress row while you stream a multi-step answer into it. Progress lives on `Comment.progress`, independent of the `agent` block, so any multi-step operation, not just an [AI agent](https://velt.dev/docs/ai/agent-comments.md), can use it.

### How It Works

1. Create a content-less comment with `progress.state: 'active'` via `addComment()`.
2. Push step updates with repeated `updateComment()` calls on the **same** `commentId`.
3. Finish by writing the real content (`commentText`, `commentHtml`, and so on) with `state: 'completed'` on that same comment.

The row renders between the last message and the reply composer. It disappears the moment the comment's `progress.state` stops being `'active'`, and the completed comment then renders as a normal reply.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> const commentId = Date.now();
>
> await commentElement.addComment({
>   annotationId: 'ANNOTATION_ID',
>   comment: {
>     commentId,
>     progress: { state: 'active', steps: [{ label: 'Getting data', state: 'active' }] },
>   },
> });
>
> await commentElement.updateComment({
>   annotationId: 'ANNOTATION_ID',
>   comment: {
>     commentId,
>     progress: { state: 'completed', steps: [{ label: 'Generating response', state: 'completed' }] },
>     commentText: 'This is the answer for your question.',
>     commentHtml: '<p>This is the answer for your question.</p>',
>   },
> });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> const commentId = Date.now();
>
> await commentElement.addComment({
>   annotationId: 'ANNOTATION_ID',
>   comment: {
>     commentId,
>     progress: { state: 'active', steps: [{ label: 'Getting data', state: 'active' }] },
>   },
> });
>
> await commentElement.updateComment({
>   annotationId: 'ANNOTATION_ID',
>   comment: {
>     commentId,
>     progress: { state: 'completed', steps: [{ label: 'Generating response', state: 'completed' }] },
>     commentText: 'This is the answer for your question.',
>     commentHtml: '<p>This is the answer for your question.</p>',
>   },
> });
> ```

### Behavior

* A comment that carries `progress` and no renderable content (no `commentText`, `commentHtml`, `commentVoiceUrl`, `attachments`, or `recorders`) doesn't count toward `annotation.comments`. It never affects reply counts, sidebar previews, resolve state, or any `comments.length` check.
* A comment with both content and `progress`, for example a completed reply, renders as a normal comment. A `failed` or `cancelled` run that produced partial output keeps that output visible and just stops showing the indicator.
* Multiple concurrent runs each get their own row, ordered by server-stamped `createdAt`. `progress.startedAt` is customer-supplied and never affects ordering.
* If an annotation's only comments are content-less progress comments, the thread doesn't render until real content is written.

### Step Labels

`updateComment()` replaces the comment wholesale, so whatever `steps` array you send is the new array; there's no server-side appending. Send one step per push, an appending list, or the full checklist up front and move the `active` marker between steps. Keep at most one step at `state: 'active'` at a time.

The rendered label is the label of the last step marked `active`, falling back to the last step's label, then to a default "Processing…" label. Step labels render verbatim and never pass through translation.

#### commentProgressStaleAfter

Time in milliseconds before a progress row with no updates is treated as stale and stops rendering. It's a staleness comparison against the comment's own `lastUpdated`, not a timeout: nothing is cancelled and no timer is created.

API Method: [`setCommentProgressStaleAfter()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#setcommentprogressstaleafter)

* Params: `commentProgressStaleAfter: number`
* Returns: `void`

Default: `600000` (10 minutes)

> [!NOTE]
>
> Non-positive and non-finite values fall back to the default. Raise this for long-running agents.

> [tab] React / Next.js
>
> Using Props:
>
> ```jsx theme={null}
> <VeltComments commentProgressStaleAfter={1800000} />
> ```
>
> Using API:
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.setCommentProgressStaleAfter(1800000);
> ```

> [tab] Other Frameworks
>
> Using Props:
>
> ```html theme={null}
> <velt-comments comment-progress-stale-after="1800000"></velt-comments>
> ```
>
> Using API:
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setCommentProgressStaleAfter(1800000);
> ```

Restyle the row with [Progress wireframes](https://velt.dev/docs/ui-customization/features/async/comments/comment-dialog/wireframes.md#progress-body), or build a fully custom one with the [Progress primitives](https://velt.dev/docs/ui-customization/features/async/comments/comment-dialog/primitives.md#veltcommentdialogprogress).

# Actions

Render customer-owned chips on a comment row. Velt never interprets a click: no annotation mutation, no `saveComment()`, no record of who clicked. Subscribe to `commentActionClicked` and handle it yourself.

### Set Actions on a Row

Set `comment.actions` for one specific row, or `annotation.actions` as the default that every row without its own list inherits.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
>
> await commentElement.updateComment({
>   annotationId: 'ANNOTATION_ID',
>   comment: {
>     commentId: 'COMMENT_ID',
>     commentText: 'This is the answer for your question.',
>     actions: [
>       { id: 'copy-response', label: 'Copy Response' },
>       { id: 'dig-deeper', label: 'Dig Deeper', metadata: { kind: 'followup' } },
>     ],
>   },
> });
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
>
> await commentElement.updateComment({
>   annotationId: 'ANNOTATION_ID',
>   comment: {
>     commentId: 'COMMENT_ID',
>     commentText: 'This is the answer for your question.',
>     actions: [
>       { id: 'copy-response', label: 'Copy Response' },
>       { id: 'dig-deeper', label: 'Dig Deeper', metadata: { kind: 'followup' } },
>     ],
>   },
> });
> ```

### Behavior

* **Inheritance, not placement.** `CommentAnnotation.actions` is the per-row default for every comment without its own `comment.actions`, regardless of who authored the row. A comment-level list overrides it for that row.
* An explicitly empty comment-level list, `actions: []` or every entry `hidden`, renders no row and does not fall back to the built-in accept/reject suggestion controls.
* A progress row never inherits annotation-level actions. Only a comment-level list set directly on the progress comment renders there.
* Each entry is validated individually: a malformed entry is skipped without suppressing its valid siblings. An entry renders when `id` is a non-empty string, `hidden` is not `true`, and it has a non-empty `label` or `icon`.
* `disabled` doesn't hide the row; it's interactive state, not visibility.
* Duplicate clicks are suppressed for 500ms, keyed on the `(annotationId, commentId, actionId)` triple, so the same action ID on different rows in a thread is suppressed independently.

#### commentActionClicked

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Hook
> const eventData = useCommentEventCallback('commentActionClicked');
>
> useEffect(() => {
>   if (eventData) {
>     console.log(eventData.actionId, eventData.scope, eventData.commentId);
>   }
> }, [eventData]);
>
> // API Method
> const commentElement = client.getCommentElement();
> const subscription = commentElement.on('commentActionClicked').subscribe((event) => {
>   console.log(event.actionId, event.scope, event.commentId);
> });
> subscription?.unsubscribe();
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> const subscription = commentElement.on('commentActionClicked').subscribe((event) => {
>   console.log(event.actionId, event.scope, event.commentId);
> });
> subscription?.unsubscribe();
> ```

* Params: none
* Event: [CommentActionClickedEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#commentactionclickedevent)

Restyle the chip row with [Actions wireframes](https://velt.dev/docs/ui-customization/features/async/comments/comment-dialog/wireframes.md#actions-body-threads-thread-card), or build a fully custom one with the [Actions primitives](https://velt.dev/docs/ui-customization/features/async/comments/comment-dialog/primitives.md#veltcommentdialogactions).

# UI/UX

#### composerMode

By default, the `Composer` in the `Comments Dialog` only shows the text input box and does not show the actions bar until the `Composer` is clicked on or the user starts typing.

You can modify this behavior by setting the `Composer Mode` prop to `"expanded"`. This will make the actions bar always visible.

To keep the default behavior you can set the property to `"default"`.

`Default: "default"`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments composerMode="expanded" />
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments composer-mode="expanded"></velt-comments>
> ```

#### commentToNearestAllowedElement

Attach comment pins to the closest allowed element when clicking on a non-allowed element.
Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments commentToNearestAllowedElement={true} />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableCommentToNearestAllowedElement();
> commentElement.disableCommentToNearestAllowedElement();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments comment-to-nearest-allowed-element="true"></velt-comments>
> ```
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableCommentToNearestAllowedElement();
> commentElement.disableCommentToNearestAllowedElement();
> ```

#### deleteThreadWithFirstComment

Whether deleting the first comment in a thread will delete the entire thread.

Default: `true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments deleteThreadWithFirstComment={false} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments delete-thread-with-first-comment="false"></velt-comments>
> ```

#### draftMode

Whether to store comments in draft if they are not submitted.

When enabled, partial comments are preserved when the dialog closes, including composer text, attachments, and recordings.

Default: `true`

**Behavior:**

* Partial comments are saved with `isDraft: true` when the dialog is closed
* The dialog shows a shake animation on the first click outside if there's unsaved content
* The `data-velt-annotation-draft` attribute is set on dialogs with unsaved content for custom styling

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments draftMode={false} />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableDraftMode();
> commentElement.disableDraftMode();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments draft-mode="false"></velt-comments>
> ```
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableDraftMode();
> commentElement.disableDraftMode();
> ```

#### lazyLoadResolvedComments

Skip fetching resolved comments on a document's initial load. Comments with a terminal status (`type === 'terminal'` in the status catalog) are excluded from the first fetch and load on demand.

API Methods: [`enableLazyLoadResolvedComments()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#enablelazyloadresolvedcomments), [`disableLazyLoadResolvedComments()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#disablelazyloadresolvedcomments)

* Params: `none`
* Returns: `void`

Default: `false`

**Behavior:**

* Selecting a terminal status, Status → All, Reset filters, the `resolved` quick filter, or a quick-filter preset that surfaces resolved threads fetches resolved comments for that document. The unlock is one-way for the document and re-locks when you navigate to a different document or organization.
* `resolvedCommentsOnDom` / [`showResolvedCommentsOnDom()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#showresolvedcommentsondom) does not unlock the fetch. It only controls whether already-loaded resolved comments render as DOM pins.
* While resolved comments are withheld, sidebar Status options for terminal statuses show no count instead of `0`. Counts return to normal after unlock.

> [!NOTE]
>
> `enableLazyLoadResolvedComments()` after resolved comments are already unlocked on the current document does not remove them.

> [tab] React / Next.js
>
> Using Props:
>
> ```jsx theme={null}
> <VeltComments lazyLoadResolvedComments={true} />
> ```
>
> Using API:
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableLazyLoadResolvedComments();
> commentElement.disableLazyLoadResolvedComments();
> ```

> [tab] Other Frameworks
>
> Using Props:
>
> ```html theme={null}
> <velt-comments lazy-load-resolved-comments="true"></velt-comments>
> ```
>
> Using API:
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableLazyLoadResolvedComments();
> commentElement.disableLazyLoadResolvedComments();
> ```

#### draftConfirmation

Show a confirmation popup before an unsent composer is saved as a draft. Requires `draftMode`.

API Methods: [`enableDraftConfirmation()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#enabledraftconfirmation), [`disableDraftConfirmation()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#disabledraftconfirmation)

* Params: `none`
* Returns: `void`

Default: `false`

**Behavior:**

* If draft mode is off, no draft is written, so there is nothing to confirm.
* Non-draft writes (edits, status, priority, assignment, deletes) never show this popup.
* **Keep Draft** (including Escape, a backdrop click, or a dialog error) saves the draft as usual. **Delete Draft** discards it.
* The comment pin stays on screen while the popup is open.
* The quoted preview shows composer plain text, else a recording count, else an attachment count. An empty preview suppresses the quoted box. Pasted markup is escaped, not rendered as HTML.

> [!NOTE]
>
> This flag adds a `velt-confirm-dialog--draft` modifier class and a quoted-preview slot to the standard delete-confirmation dialog. Existing delete confirmations for comments, areas, arrows, tags, and recorders are unchanged. See [Confirmation Dialog](https://velt.dev/docs/ui-customization/features/async/comments/confirm-dialog.md#preview) to customize the preview.

> [tab] React / Next.js
>
> Using Props:
>
> ```jsx theme={null}
> <VeltComments draftMode={true} draftConfirmation={true} />
> ```
>
> Using API:
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableDraftMode();
> commentElement.enableDraftConfirmation();
> ```

> [tab] Other Frameworks
>
> Using Props:
>
> ```html theme={null}
> <velt-comments draft-mode="true" draft-confirmation="true"></velt-comments>
> ```
>
> Using API:
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableDraftMode();
> commentElement.enableDraftConfirmation();
> ```

#### enableCollapsedComments

Control whether a comment dialog collapses its middle replies when a thread has more than two comments.

* When `false` (default), the dialog renders every comment in the thread.
* When `true`, the dialog renders only the first and last comment, with an "N more replies" divider in between. Clicking the divider expands the hidden comments inline.

There is no separate "Show all comments" or "Hide all comments" button that end users can toggle at runtime. This flag (or the equivalent API methods below) drives the expanded vs. collapsed layout.

`Default: false`

> [tab] React / Next.js
>
> Using Props:
>
> ```jsx theme={null}
> <VeltComments collapsedComments={true} />
> ```
>
> Using API:
>
> ```javascript theme={null}
> const commentElement = client.getCommentElement();
> // To enable collapsed comments
> commentElement.enableCollapsedComments();
> // To disable collapsed comments
> commentElement.disableCollapsedComments();
> ```

> [tab] Other Frameworks
>
> Using Props:
>
> ```html theme={null}
> <velt-comments collapsed-comments="true"></velt-comments>
> ```
>
> Using API:
>
> ```javascript theme={null}
> const commentElement = Velt.getCommentElement();
> // To enable collapsed comments
> commentElement.enableCollapsedComments();
> // To disable collapsed comments
> commentElement.disableCollapsedComments();
> ```

#### enableFullExpanded

* You can control whether comments should be shown in fully expanded state by default.
* Available on all comment-related components and can be controlled via props or API methods.

`Default: false`

> [tab] React / Next.js
>
> Using Props:
>
> ```jsx theme={null}
> // Apply this change globally to all types of comments
> <VeltComments fullExpanded={true} />
>
> // Apply this change only in comments sidebar
>
> <VeltCommentsSidebar fullExpanded={true} />
>
> // Apply this change only in inline comments section
>
> <VeltInlineCommentsSection fullExpanded={true} />
>
> // Apply this change only in the standalone comment thread
>
> <VeltCommentThread fullExpanded={true} />
>
> ```
>
> Using API:
>
> ```js theme={null}
> // API Method
> const commentElement = client.getCommentElement();
> commentElement.enableFullExpanded();
> commentElement.disableFullExpanded();
> ```

> [tab] Other Frameworks
>
> Using Props:
>
> ```html theme={null}
> <!-- Apply this change globally to all types of comments -->
> <velt-comments full-expanded="true"></velt-comments>
>
> <!-- Apply this change only in comments sidebar -->
>
> <velt-comments-sidebar full-expanded="true"></velt-comments-sidebar>
>
> <!-- Apply this change only in inline comments section -->
>
> <velt-inline-comments-section full-expanded="true"></velt-inline-comments-section>
>
> <!-- Apply this change only in the standalone comment thread -->
>
> <velt-comment-thread full-expanded="true"></velt-comment-thread>
>
> ```
>
> Using API:
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableFullExpanded();
> commentElement.disableFullExpanded();
> ```

#### enableShortUserName

You can control whether long user names should be shortened. For long names, this will first create an initial of the second name and if the name is still long, it will truncate it with ellipses.

Default: `true`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments shortUserName={false} />
> ```
>
> **Using API:**
>
> ```javascript theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableShortUserName();
> commentElement.disableShortUserName();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments short-user-name="false"></velt-comments>
> ```
>
> **Using API:**
>
> ```javascript theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableShortUserName();
> commentElement.disableShortUserName();
> ```

#### enableSignInButton

![](https://mintcdn.com/velt/gY7ilEx2g4g3-HVe/images/sign-in-button.png?fit=max\&auto=format\&n=gY7ilEx2g4g3-HVe\&q=85\&s=889a09f02a9a9bd1a51c61a8044e9077)

Whether to enable Sign In button on comment dialog when user is anonymous or signed out.

`Default: false`

This allows anonymous or signed out users to still read the comments but encourages them to sign in if they want to respond to the comments.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments signInButton={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments sign-in-button="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableSignInButton();
> commentElement.disableSignInButton();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableSignInButton();
> commentElement.disableSignInButton();
> ```

#### enableSidebarButtonOnCommentDialog

![](https://mintcdn.com/velt/gY7ilEx2g4g3-HVe/images/sidebar-button-on-comment-dialog.png?fit=max\&auto=format\&n=gY7ilEx2g4g3-HVe\&q=85\&s=6b5a81b9667f77d96428759d5a819a86)

Whether the Sidebar Button on Comment Dialogs show up.

`Default: true`

By Default, each Comment Dialog has a button at the bottom that will open the Comments Sidebar when clicked.

To disable it, you can set it to false:

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments sidebarButtonOnCommentDialog={true} />
> ```
>
> **Using API methods:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableSidebarButtonOnCommentDialog();
> commentElement.disableSidebarButtonOnCommentDialog();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```jsx theme={null}
> <velt-comments sidebar-button-comment-dialog="true"></velt-comments>
> ```
>
> **Using API methods:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableSidebarButtonOnCommentDialog();
> commentElement.disableSidebarButtonOnCommentDialog();
> ```

#### enableDeleteReplyConfirmation

You can enable a confirmation dialog before deleting a reply in comment threads. This feature helps prevent accidental deletions and improves user experience.

> [tab] React / Next.js
>
> Using Props:
>
> ```jsx theme={null}
> <VeltComments deleteReplyConfirmation={true} />
> ```
>
> Using API:
>
> ```javascript theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableDeleteReplyConfirmation();
> commentElement.disableDeleteReplyConfirmation();
> ```

> [tab] Other Frameworks
>
> Using Props:
>
> ```html theme={null}
> <velt-comments delete-reply-confirmation="true"></velt-comments>
> ```
>
> Using API:
>
> ```javascript theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableDeleteReplyConfirmation();
> commentElement.disableDeleteReplyConfirmation();
> ```

#### enableMobileMode

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/mobile-mode.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=e70906b207c4c2f318f7cfdb7f4a8510)

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/mobile-mode-composer.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=4f0119d1f599a775d4e1deee0c2009c2)

Whether mobile mode is enabled.

When mobile mode is enabled and the screen width is small enough, comment windows will appear fixed to the bottom of the screen and full width instead of the usual popup window.

`Default: false`

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments mobileMode={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments mobile-mode="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableMobileMode();
> commentElement.disableMobileMode();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableMobileMode();
> commentElement.disableMobileMode();
> ```

#### enableCommentPinHighlighter

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/pin-highlighter-outline.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=8c363c925a3a675679053f5f5715529b)

Whether the pin highlighter outline is enabled.

`Default: true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments commentPinHighlighter={false} />
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments comment-pin-highlighter="false"></velt-comments>
> ```

API Methods:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableCommentPinHighlighter(); // to enable comment pin highlight
> commentElement.disableCommentPinHighlighter(); // to disable comment pin highlight
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableCommentPinHighlighter(); // to enable comment pin highlight
> commentElement.disableCommentPinHighlighter(); // to disable comment pin highlight
> ```

#### pinDrag

Whether comment pins can be dragged to reposition them.

`Default: true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments pinDrag={false} />
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments pin-drag="false"></velt-comments>
> ```

API Methods:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enablePinDrag(); // to enable comment pin drag
> commentElement.disablePinDrag(); // to disable comment pin drag
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enablePinDrag(); // to enable comment pin drag
> commentElement.disablePinDrag(); // to disable comment pin drag
> ```

#### enableDialogOnHover

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/show-dialog-on-hover.gif?s=4c58970e8c5d6185fd6955cfa9e865df)

Whether the comment dialog shows on hover over the comment pin or the target element.

`Default: true`

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments dialogOnHover={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments dialog-on-hover="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableDialogOnHover();
> commentElement.disableDialogOnHover();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableDialogOnHover();
> commentElement.disableDialogOnHover();
> ```

#### enableFloatingCommentDialog

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/floating-comment-dialog.gif?s=21a58debadd5a1d8eca880200bcc03d9)

Whether floating comment dialog is shown next to comment pin on hover or click.

`Default: true`

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments floatingCommentDialog={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments floating-comment-dialog="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableFloatingCommentDialog();
> commentElement.disableFloatingCommentDialog();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableFloatingCommentDialog();
> commentElement.disableFloatingCommentDialog();
> ```

#### excludeLocationIds

Use this to filter out Comments at a specific Location for certain Users.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const locationIds = ['location1', 'location2']; // list of location ids
> client.excludeLocationIds(locationIds);
> ```
>
> To reset it, you can pass an empty array:
>
> ```jsx theme={null}
> client.excludeLocationIds([]);
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const locationIds = ['location1', 'location2']; // list of location ids
> Velt.excludeLocationIds(locationIds);
> ```
>
> To reset it, you can pass an empty array:
>
> ```jsx theme={null}
> Velt.excludeLocationIds([]);
> ```

#### enableReplyAvatars

This shows the avatars of unique users who have replied to a comment.

* `replyAvatars`: Whether the reply avatar component is enabled.
* `maxReplyAvatars`: The maximum number of reply avatars to show. It will show the count of remaining unique users as the next avatar.

`Default: false`

> [tab] React / Next.js
>
> **Using props:**
>
> ```jsx theme={null}
> <VeltComments maxReplyAvatars={2} replyAvatars={true} />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentsElement = client.getCommentElement();
> commentsElement.enableReplyAvatars(); // Enables the reply avatar component.
> commentsElement.disableReplyAvatars(); // Disables the reply avatar component.
> commentsElement.setMaxReplyAvatars(2); // Sets the maximum number of reply avatars to show.
> ```

> [tab] Other Frameworks
>
> **Using props:**
>
> ```html theme={null}
> <velt-comments max-reply-avatars="2" reply-avatars="true"></velt-comments>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentsElement = Velt.getCommentElement();
> commentsElement.enableReplyAvatars(); // Enables the reply avatar component.
> commentsElement.disableReplyAvatars(); // Disables the reply avatar component.
> commentsElement.setMaxReplyAvatars(2); // Sets the maximum number of reply avatars to show.
> ```

#### filterCommentsOnDom

* Filter out comments in the DOM when they are filtered in the sidebar.
* When the sidebar is closed (default mode) or unmounted (embed mode), the DOM filter will be removed.
* **Dual-gate behavior:** When `setCommentSidebarData()` is also active, this feature applies an AND — on-page pins must satisfy both the active sidebar filter criteria and the custom id list from `setCommentSidebarData()`. Drafts (`isDraft: true`) bypass both gates so an in-progress unposted comment is never filtered out from under the user.

`Default: false`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments filterCommentsOnDom={true} />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableFilterCommentsOnDom();
> commentElement.disableFilterCommentsOnDom();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments filter-comments-on-dom="true"></velt-comments>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableFilterCommentsOnDom();
> commentElement.disableFilterCommentsOnDom();
> ```

#### focusPageModeComposer

Focus the page mode composer input field programmatically.

Use this to direct user attention to the page mode composer.

API Method: [`focusPageModeComposer()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#focuspagemodecomposer)

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using Hook
> const commentElement = useCommentUtils();
> commentElement.focusPageModeComposer();
>
> // Using API Method
> const commentElement = client.getCommentElement();
> commentElement.focusPageModeComposer();
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.focusPageModeComposer();
> ```

#### onSidebarButtonOnCommentDialogClick

Use this to act on clicks on the Sidebar Button at the bottom of the Comment Dialog.

![](https://mintcdn.com/velt/Y46CMUqidobLXMZ7/images/customization/onSidebarOnCommentDialogClick.png?fit=max\&auto=format\&n=Y46CMUqidobLXMZ7\&q=85\&s=dc11b6799510579241a5f60bdf4d80b8)

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments
>   onSidebarButtonOnCommentDialogClick={(event) => yourMethod(event)}
> />
> ```
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const commentDialogSidebarClickEvent = useCommentDialogSidebarClickHandler();
> useEffect(() => {
>   console.log("CommentDialog Sidebar button clicked");
> }, [commentDialogSidebarClickEvent]);
> ```
>
> **Using API methods:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> let subscription = commentElement
>   .onSidebarButtonOnCommentDialogClick()
>   .subscribe((event) => yourMethod(event));
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

> [tab] HTML
>
> **Using Props:**
>
> ```jsx theme={null}
> <velt-comments onsidebarbuttononcommentdialogclick="yourMethod(event)"></velt-comments>
> ```
>
> **Using API Methods:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> let subscription = commentElement
>   .onSidebarButtonOnCommentDialogClick()
>   .subscribe((event) => yourMethod(event));
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

#### onSignIn

When the user clicks on the sign in button, we will emit an `onSignIn` event that you can handle with your own sign in method.

No data is passed with the event.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments onSignIn={() => yourSignInMethod()} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const veltCommentsTag = document.querySelector('velt-comments');
>
> veltCommentsTag?.addEventListener('onSignIn', (event) => {
> console.log('**_ onCommentSignIn _**');
> console.log(event.detail);
> });
>
> ```

#### showCommentsOnDom

Whether comments are shown on the DOM.

`Default: true`

By default, all the comments will be visible on DOM whenever we are able to detect to elements for that. But users can hide it from DOM if required.

There are 2 ways to show/hide comments on DOM:

Configuring attributes on the React Component:

> [tab] React / Next.js
>
> ```js theme={null}
> {/* `true` to show comments, `false` to hide comments */}
> <VeltComments commentsOnDom={false} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <!-- `true` to show comments, `false` to hide comments -->
> <velt-comments comments-on-dom="false"></velt-comments>
> ```

Using API methods:

> [tab] React / Next.js
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
> // to show comments on DOM
> commentElement.showCommentsOnDom();
> // to hide comments on DOM
> commentElement.hideCommentsOnDom();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> // to show comments on DOM
> commentElement.showCommentsOnDom();
> // to hide comments on DOM
> commentElement.hideCommentsOnDom();
> ```

#### showResolvedCommentsOnDom

Whether to show resolved comments on the DOM.

`Default: false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments resolvedCommentsOnDom={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments resolved-comments-on-dom="true"></velt-comments>
> ```

API Methods:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> // To show resolved comments on dom
> commentElement.showResolvedCommentsOnDom();
> // To hide resolved comments on dom
> commentElement.hideResolvedCommentsOnDom();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> // To show resolved comments on dom
> commentElement.showResolvedCommentsOnDom();
> // To hide resolved comments on dom
> commentElement.hideResolvedCommentsOnDom();
> ```

#### updateCommentDialogPosition

* Sometimes when you manually set the position of the Comment Pin, the Comment Dialog might not position itself near the pin in certain scenarios like scrolling, zooming the page when the comment dialog is open.
* Use this to manually trigger an update. The dialog will reposition itself near the pin.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.updateCommentDialogPosition();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.updateCommentDialogPosition();
> ```

You can add custom lists at two levels: a. on the CommentAnnotation and b. on the Comment.

#### Link Callback

Enable a callback when users click on links rendered in comment content. When enabled, links won’t automatically open; instead an event is emitted.

How to use:

* By default `linkCallback` is `false`.
* When `false`, clicking a link opens it directly and no callback is triggered.
* When `true`, clicking a link does not open it; instead a `linkClicked` event is emitted so you can handle navigation.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using Props
> <VeltComments linkCallback={true} />
>
> // Using Hooks
> const linkEvent = useCommentEventCallback('linkClicked')
> useEffect(() => {
> if (linkEvent) {
> console.log('linkClicked', linkEvent);
> }
> }, [linkEvent]);
>
> // Using API
> const commentElement = client.getCommentElement();
> commentElement.on('linkClicked').subscribe((linkData) => {
> console.log('linkClicked', linkData);
> });
>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments link-callback="true"></velt-comments>
>
> <script>
>   const commentElement = Velt.getCommentElement();
>   commentElement.on('linkClicked').subscribe((linkData) => {
>     console.log('Comment link clicked:', linkData);
>   });
> </script>
> ```

Types:

```ts theme={null}
export interface LinkClickedEvent {
  text: string;
  link: string;
  commentAnnotation: CommentAnnotation;
  commentId: Number;
  metadata?: VeltEventMetadata;
}
```

#### commentBubbleClicked

Listen to when a comment bubble is clicked.

This event is triggered whenever a user clicks on a comment bubble. You can use this to implement custom actions like navigation or analytics tracking.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using Hook
> const commentBubbleClickedEvent = useCommentEventCallback('commentBubbleClicked');
> useEffect(() => {
>   if (commentBubbleClickedEvent) {
>     console.log('Comment bubble clicked:', commentBubbleClickedEvent);
>   }
> }, [commentBubbleClickedEvent]);
>
> // Using API
> const commentElement = client.getCommentElement();
> commentElement.on('commentBubbleClicked').subscribe((eventData) => {
> console.log('Comment bubble clicked:', eventData);
> });
>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <script>
>   const commentElement = Velt.getCommentElement();
>   commentElement.on('commentBubbleClicked').subscribe((eventData) => {
>     console.log('Comment bubble clicked:', eventData);
>   });
> </script>
> ```

**Event Type**: [`CommentBubbleClickedEvent`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentbubbleclickedevent)

```ts theme={null}
export interface CommentBubbleClickedEvent {
  annotationId: string;
  commentAnnotation: CommentAnnotation;
  metadata?: VeltEventMetadata;
}
```

# Extra Information

#### enableCommentIndex

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/index-indicator.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=cba1ca1d96d4f9447e5cc32fb62d4865)

Whether comment index is enabled.

`Default: false`

This appears in the comment sidebar and on the comment pins. When this is on, we show a small icon indicating the comment index in the order of creation date. This enables users to find and navigate to the desired comment quickly.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments commentIndex={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments comment-index="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableCommentIndex();
> commentElement.disableCommentIndex();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableCommentIndex();
> commentElement.disableCommentIndex();
> ```

#### enableDeviceInfo

![](https://mintcdn.com/velt/kAkMSIYF4ZlrlwLm/images/device-info.png?fit=max\&auto=format\&n=kAkMSIYF4ZlrlwLm\&q=85\&s=4e5f88e1f638a5c7d3cbec7dcc88fe79)

Whether device type indicator is enabled.

`Default: false`

When this is on, we show additional information in the `Comment Thread` indicating which device the comment was created on. This is useful especially for design tools, where additional context is needed for debugging issues.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments deviceInfo={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments device-info="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableDeviceInfo();
> commentElement.disableDeviceInfo();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableDeviceInfo();
> commentElement.disableDeviceInfo();
> ```

#### enableDeviceIndicatorOnCommentPins

![](https://mintcdn.com/velt/kAkMSIYF4ZlrlwLm/images/device-info-pin.png?fit=max\&auto=format\&n=kAkMSIYF4ZlrlwLm\&q=85\&s=3255d9d2d06a01169e144a9e91f00d69)

Whether the device type indicator on `Comment Pins` is enabled.

`Default: false`

When this is on, we show a small device type icon on the `Comment Pin` indicating which device the comment was created on. This is useful especially for design tools, where additional context is needed for debugging issues.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments deviceIndicatorOnCommentPins={true} />
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments device-indicator-on-comment-pins="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableDeviceIndicatorOnCommentPins();
> commentElement.disableDeviceIndicatorOnCommentPins();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableDeviceIndicatorOnCommentPins();
> commentElement.disableDeviceIndicatorOnCommentPins();
> ```

#### enableGhostComments

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/ghost-comment-pin.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=73b8c5e9d95200a26e589e5551abc5f3)

![](https://mintcdn.com/velt/kAkMSIYF4ZlrlwLm/images/ghost-comment-dialog-box.png?fit=max\&auto=format\&n=kAkMSIYF4ZlrlwLm\&q=85\&s=8b52e18e25089c38469ec6974571c095)

Whether to show ghost comments on the DOM.

`Default: false`

Ghost comments are comments that were once linked to certain content on the DOM but that content is no longer available. If this is on, we display ghost comments in gray, close to where they were originally positioned on the DOM.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments ghostComments={true} />
> ```
>
> **Using API methods:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableGhostComments();
> commentElement.disableGhostComments();
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments ghost-comments="true"></velt-comments>
> ```
>
> **Using API methods:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableGhostComments();
> commentElement.disableGhostComments();
> ```

#### enableGhostCommentsIndicator

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/ghost-comment-sidebar.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=678c427b727079b54ec81d2e9efbf313)

Whether to show ghost comment labels in the comment sidebar.

`Default: true`

Ghost comments are always shown in the comments sidebar so that users can see the history of all comments. If this is on, we show a label on the comment in the sidebar indicating that the original content on which this comment was added is no longer available. This sets better expectations with the users.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments ghostCommentsIndicator={true} />
> ```
>
> **Using API methods:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableGhostCommentsIndicator();
> commentElement.disableGhostCommentsIndicator();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments ghost-comments-indicator="true"></velt-comments>
> ```
>
> **Using API methods:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableGhostCommentsIndicator();
> commentElement.disableGhostCommentsIndicator();
> ```

# Special File Type Support

#### Iframe Container Support

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/iframe-comment.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=83f6a57f334da3de4c6e0aedc4e1489e)

* To enable comments on an iframe, add `data-velt-iframe-container="true"` to the iframe's container element.
* Note this will not insert the comments inside the contents of the iframe, but rather on top of the iframe.

```html theme={null}
<div data-velt-iframe-container="true">
  <iframe
    src="https://www.wikipedia.org/"
    width="500px"
    height="500px"
  ></iframe>
</div>
```

#### data-velt-pdf-viewer

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/pdf-comments.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=47c78b07508421cac669cecfaa1c6100)

To support comments on top of a pdf viewer, add the `data-velt-pdf-viewer="true"` attribute in the container element of the pdf viewer.

```html theme={null}
<!-- Add this attribute to the container of your pdf viewer -->
<div id="viewerContainer" data-velt-pdf-viewer="true">
  <!-- Your pdf viewer here -->
  <div id="viewer" class="pdfViewer"></div>
</div>
```

#### svgAsImg

* By default, Velt SDK treats SVGs as layered elements.
* If you want to treat SVGs as flat images, you can use this.
* Default: `false`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments svgAsImg={true} />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableSvgAsImg();
> commentElement.disableSvgAsImg();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments svg-as-img="true"></velt-comments>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableSvgAsImg();
> commentElement.disableSvgAsImg();
> ```

# Keyboard Controls

#### enableHotkey

Whether Hotkeys are enabled or not. For now, the only hotkey supported is pressing `c` to enable `comment mode`.

`Default: false`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments hotkey={false} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableHotkey();
> commentElement.disableHotkey();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments hotkey="true"></velt-comments>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableHotkey();
> commentElement.disableHotkey();
> ```

#### enableEnterKeyToSubmit

* By default, pressing `enter` will add a new line and pressing `shift` + `enter` will submit a comment.
* You can change this default behavior so that pressing `enter` will submit a comment by setting the `enterKeyToSubmit` property to `true`.

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments enterKeyToSubmit={true} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableEnterKeyToSubmit();
> commentElement.disableEnterKeyToSubmit();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```jsx theme={null}
> <velt-comments enter-key-to-submit="true"></velt-comments>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableEnterKeyToSubmit();
> commentElement.disableEnterKeyToSubmit();
> ```

#### enableDeleteOnBackspace

* Use this to enable or disable deleting comments when the backspace key is pressed.

Default: `enabled`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments deleteOnBackspace={false} />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableDeleteOnBackspace();
> commentElement.disableDeleteOnBackspace();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```jsx theme={null}
> <velt-comments delete-on-backspace="false"></velt-comments>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableDeleteOnBackspace();
> commentElement.disableDeleteOnBackspace();
> ```

# Moderation

#### enableModeratorMode

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/moderator-mode.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=1cc209fbf53680874324c4c5679d5d8a)

Whether comments require moderator approval.

`Default: false`

By default, when a user adds a comment it is visible to all authenticated users on the same `document`. Moderator mode makes visibility of all comments private to only `admin` users and the comment author. Admin users will see an approve button on the comment dialog. Once approved the comment will be visible to all users who can access the `document`.

You can set some users as `admin` by setting the `isAdmin` property in the User object, during the `identify()` call.

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments moderatorMode={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments moderator-mode="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableModeratorMode();
> commentElement.disableModeratorMode();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableModeratorMode();
> commentElement.disableModeratorMode();
> ```

#### enableResolveStatusAccessAdminOnly

* Restrict the resolve action to admin users and the comment author only.

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments resolveStatusAccessAdminOnly={true} />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> // To enable resolve status access admin only
> commentElement.enableResolveStatusAccessAdminOnly();
> // To disable resolve status access admin only
> commentElement.disableResolveStatusAccessAdminOnly();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments resolve-status-access-admin-only="true"></velt-comments>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> // To enable resolve status access admin only
> commentElement.enableResolveStatusAccessAdminOnly();
> // To disable resolve status access admin only
> commentElement.disableResolveStatusAccessAdminOnly();
> ```

#### approveCommentAnnotation

* Approves a comment annotation in moderator mode
* Params: [ApproveCommentAnnotationRequest](https://velt.dev/docs/api-reference/sdk/models/data-models.md#approvecommentannotationrequest)
* Returns: [ApproveCommentAnnotationEvent](https://velt.dev/docs/api-reference/sdk/models/data-models.md#approvecommentannotationevent)

> [tab] React / Next.js
>
> ```jsx theme={null}
> const approveCommentAnnotationRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> // Hook
> const { approveCommentAnnotation } = useApproveCommentAnnotation();
> const approveCommentAnnotationEvent = await approveCommentAnnotation(approveCommentAnnotationRequest);
>
> // API Method
> const commentElement = client.getCommentElement();
> const approveCommentAnnotationEvent = await commentElement.approveCommentAnnotation(approveCommentAnnotationRequest);
>
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> const approveCommentAnnotationRequest = {
>   annotationId: 'ANNOTATION_ID'
> };
>
> const commentElement = Velt.getCommentElement();
> const approveCommentAnnotationEvent = await commentElement.approveCommentAnnotation(approveCommentAnnotationRequest);
> ```

#### enableSuggestionMode

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/images/accept-reject.png?fit=max\&auto=format\&n=gAz_vLsG-ukKamYM\&q=85\&s=83fbf205b67c4e9f7635e72ccd2d8c33)

Whether to enable suggestion mode to accept or reject comments.

`Default: false`

> [tab] React / Next.js
>
> To accept comments, set the `suggestionMode` attribute to `true`.
>
> ```js theme={null}
> <VeltComments suggestionMode={true} />
> ```

> [tab] Other Frameworks
>
> To accept comments, set the `suggestion-mode` attribute to `true`.
>
> ```html theme={null}
> <velt-comments suggestion-mode="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableSuggestionMode();
> commentElement.disableSuggestionMode();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableSuggestionMode();
> commentElement.disableSuggestionMode();
> ```

#### enableReadOnly

Control whether comments are in read-only mode. When enabled, any features requiring user interaction (e.g., Composer, Reactions, Status) will be removed.

Default: `false`

> [tab] React / Next.JS
>
> Using Props:
>
> ```jsx theme={null}
> <VeltComments readOnly={true} />
> ```
>
> Using API:
>
> ```js theme={null}
>   const commentElement = client.getCommentElement();
>   commentElement.enableReadOnly();
>   commentElement.disableReadOnly();
> ```

> [tab] Other Frameworks
>
> Using Props:
>
> ```html theme={null}
> <velt-comments read-only="true"></velt-comments>
> ```
>
> Using API:
>
> ```js theme={null}
>   const commentElement = Velt.getCommentElement();
>   commentElement.enableReadOnly();
>   commentElement.disableReadOnly();
> ```

# Comment Read Status

#### enableSeenByUsers

Control whether the "Seen By" feature is enabled for comments. When enabled, it shows which users have seen each comment.

Default: `true`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments seenByUsers={false} />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableSeenByUsers();
> commentElement.disableSeenByUsers();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments seen-by-users="false"></velt-comments>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableSeenByUsers();
> commentElement.disableSeenByUsers();
> ```

#### setUnreadIndicatorMode

Whether `verbose` mode is enabled for unread `Comments`.

`Default: 'minimal'`

Unread `Comments` can be in `minimal` mode or `verbose` mode.

In `minimal` mode, a small red dot indicator appears for unread `Comments`.

In `verbose` mode, a larger badge with the text "UNREAD" will appear for unread `Comments`.

![](https://mintcdn.com/velt/gY7ilEx2g4g3-HVe/images/unread-compare.png?fit=max\&auto=format\&n=gY7ilEx2g4g3-HVe\&q=85\&s=205adde0a88a97a0ffdb82c06c174a78)

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments unreadIndicatorMode={"verbose"} />
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments unread-indicator-mode="verbose"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.setUnreadIndicatorMode("verbose"); // use badge with text UNREAD
> commentElement.setUnreadIndicatorMode("minimal"); // use small red dot indicator
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setUnreadIndicatorMode("verbose"); // use badge with text UNREAD
> commentElement.setUnreadIndicatorMode("minimal"); // use small red dot indicator
> ```

# Toggle Comment Types

#### enableAreaComment

Area comments allows users to draw a rectangle and attach a comment to it.
Use this to enable or disable area comments.

Default: `true`

![](https://mintcdn.com/velt/kAkMSIYF4ZlrlwLm/images/enable-disable-area-comments.png?fit=max\&auto=format\&n=kAkMSIYF4ZlrlwLm\&q=85\&s=3cced9a9ff910f884dc76c6960374ae2)

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments areaComment={false} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableAreaComment();
> commentElement.disableAreaComment();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```jsx theme={null}
> <velt-comments area-comment="false"></velt-comments>
> ```
>
> Using API Method:
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableAreaComment();
> commentElement.disableAreaComment();
> ```

#### enablePopoverMode

> [!NOTE]
>
> For a complete setup guide for Popover mode, [read
> here](https://velt.dev/docs/async-collaboration/comments/setup/popover.md).

Whether Popover Mode is enabled.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments popoverMode={true}/>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enablePopoverMode();
> commentElement.disablePopoverMode();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments popover-mode="true"></velt-comments> 
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enablePopoverMode();
> commentElement.disablePopoverMode();
> ```

#### enableStreamMode

> [!NOTE]
>
> For a complete setup guide for Stream mode, [read
> here](https://velt.dev/docs/async-collaboration/comments/setup/stream.md).

Whether Stream Mode is enabled.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments streamMode={true}/>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableStreamMode();
> commentElement.disableStreamMode();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments stream-mode="true"></velt-comments>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableStreamMode();
> commentElement.disableStreamMode();
> ```

#### enableTextMode

> [!NOTE]
>
> For a complete setup guide for Text mode, [read
> here](https://velt.dev/docs/async-collaboration/comments/setup/text.md).

Whether Text Mode is enabled.

Default: `true`

![](https://mintcdn.com/velt/gY7ilEx2g4g3-HVe/images/text-comment.png?fit=max\&auto=format\&n=gY7ilEx2g4g3-HVe\&q=85\&s=e2938519d890a5c020d1da5407c4557c)

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments textMode={true}/>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableTextComments();
> commentElement.disableTextComments();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments text-mode="true"></velt-comments> 
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableTextComments();
> commentElement.disableTextComments();
> ```

#### restrictTextSearchToAnchor

* Controls how the SDK re-locates a text comment's highlight when the commented text can no longer be found inside its original anchor element.
* When disabled (default): if the stored text is missing from the anchor element, the SDK falls back to a wider search — `document.body` for body-anchored comments, or the comment's location element for location-scoped comments — before ghosting the comment. This recovers highlights after the DOM is re-rendered or restructured.
* When enabled: the search is restricted to the anchor element only. If the anchor text is gone, the comment ghosts immediately with no fallback. Use this when your app deliberately reuses the same text across regions and you never want a comment to re-bind outside its original anchor.

Default: `false`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments restrictTextSearchToAnchor={true} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableRestrictTextSearchToAnchor();
> commentElement.disableRestrictTextSearchToAnchor();
> ```

> [tab] Other Frameworks
>
> **Using HTML Attribute:**
>
> ```html theme={null}
> <velt-comments restrict-text-search-to-anchor="true"></velt-comments>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableRestrictTextSearchToAnchor();
> commentElement.disableRestrictTextSearchToAnchor();
> ```

#### enableInlineCommentMode

![](https://mintcdn.com/velt/gY7ilEx2g4g3-HVe/images/text-comment-opened.png?fit=max\&auto=format\&n=gY7ilEx2g4g3-HVe\&q=85\&s=25a5a817cb85532ce33b9bf08f89d4e5)

Whether In-line comment mode is enabled.

When In-line comment mode is enabled, comments will appear under the text they are associated with in the DOM, instead of as a pop up window.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments inlineCommentMode={true}/>
> ```
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableInlineCommentMode();
> commentElement.disableInlineCommentMode();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments inline-comment-mode="true"></velt-comments> 
> ```
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableInlineCommentMode();
> commentElement.disableInlineCommentMode();
> ```

#### enableMultiThread

* By default comments are single threaded.
* You can make it multithreaded by setting `multiThread` prop to `true`.
* If you had previously used a wireframe for the comment dialog, you will need to add the [multithread wireframe](https://velt.dev/docs/ui-customization/features/async/comments/multithread-comments/wireframes.md).
* Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments multiThread={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments multi-thread="true"></velt-comments>
> ```

#### collapsedRepliesPreview

When enabled, a comment dialog's non-selected preview state shows the collapsed thread teaser (first comment, a "Show N replies…" divider, and the last comment) instead of only the first comment. Clicking the divider selects and expands the dialog in one step.

API Methods: [`enableCollapsedRepliesPreview()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#enablecollapsedrepliespreview), [`disableCollapsedRepliesPreview()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#disablecollapsedrepliespreview)

* Params: `none`
* Returns: `void`

Default: `false`

> [!NOTE]
>
> This flag is also exposed as the `collapsedRepliesPreview` wireframe variable (boolean, default `false`) on the comment dialog's more reply slot.

> [tab] React / Next.js
>
> Using Props:
>
> ```jsx theme={null}
> <VeltComments collapsedRepliesPreview={true} />
> ```
>
> Using API:
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> // Enable the collapsed teaser in the non-selected state
> commentElement.enableCollapsedRepliesPreview();
> // Revert to the default (only the first comment shown when not selected)
> commentElement.disableCollapsedRepliesPreview();
> ```

> [tab] Other Frameworks
>
> Using Props:
>
> ```html theme={null}
> <velt-comments collapsed-replies-preview="true"></velt-comments>
> ```
>
> Using API:
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> // Enable the collapsed teaser in the non-selected state
> commentElement.enableCollapsedRepliesPreview();
> // Revert to the default (only the first comment shown when not selected)
> commentElement.disableCollapsedRepliesPreview();
> ```

# Comment Tool

#### context

* Add `context` to the `Velt Comment Tool` component to associate custom metadata with comments created using that tool.
* Predefine context directly within the component itself.
* Currently, this feature is specific to popover comments. This allows you to, for example, assign unique context to each cell in a table if you place a `Velt Comment Tool` in each cell.
* The `context` prop accepts an object with key-value pairs.

> [tab] React / Next.js
>
> ```jsx theme={null}
> // For popover comments
> <VeltCommentTool context={{ key1: 'value1' }} />
> ```

> [tab] HTML
>
> ```html theme={null}
> <!-- For popover comments. Make sure to stringify the context object. -->
> <velt-comment-tool context='{"key1": "value1"}'></velt-comment-tool>
> ```

#### contextInPageModeComposer

Pass context data to the page mode composer when opening the comment sidebar via the comment tool. Context automatically clears when the sidebar closes.

API Methods: [`enableContextInPageModeComposer()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#enablecontextinpagemodecomposer), [`disableContextInPageModeComposer()`](https://velt.dev/docs/api-reference/sdk/api/api-methods#disablecontextinpagemodecomposer)

* Params: `none`
* Returns: `void`

> [!NOTE]
>
> For programmatically setting context data, see
> [`setContextInPageModeComposer()`](#setcontextinpagemodecomposer).

> [tab] React / Next.js
>
> ```jsx theme={null}
> // Using props
> import { VeltCommentTool } from '@veltdev/react';
>
> <VeltCommentTool
>   contextInPageModeComposer={true}
>   context={{ section: "header", elementId: "nav-menu" }}
> />
>
> // Using API methods
> const commentElement = client.getCommentElement();
> commentElement.enableContextInPageModeComposer();
> commentElement.disableContextInPageModeComposer();
>
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comment-tool
>   context-in-page-mode-composer="true"
>   context='{"section": "header", "elementId": "nav-menu"}'>
> </velt-comment-tool>
>
> <script>
> const commentElement = Velt.getCommentElement();
> commentElement.enableContextInPageModeComposer();
> commentElement.disableContextInPageModeComposer();
> </script>
> ```

#### enableCommentMode

![](https://mintcdn.com/velt/2O8vk8YlVD4Kq-ni/images/comment-mode-on-off.png?fit=max\&auto=format\&n=2O8vk8YlVD4Kq-ni\&q=85\&s=091c57331bfdf262d0366cef8269a005)

Turns Comment mode on or off.

When you click on the comment tool, it turns on comment mode and user can attach comment to any element on the DOM. Using this method you can programmatically turn on the commenting mode.

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableCommentMode();
> commentElement.disableCommentMode();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableCommentMode();
> commentElement.disableCommentMode();
> ```

#### onCommentModeChange

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/onCommentModeChange.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=8cbe4996ca371931b658c3270a0e1e28)

The comment mode is toggled on and off when you click on the Comment Tool.

> [tab] React / Next.js with Hooks
>
> The `useCommentModeState()` hook can be used to get the Comment mode without having to subscribe to changes. When the Comment mode changes, the hook return value will update.
>
> The subscription is automatically unsubscribed when the component dismounts.
>
> ```jsx theme={null}
> import { useCommentModeState } from "@veltdev/react";
>
> export default function YourDocument() {
>   let commentModeState = useCommentModeState();
>
>   return <div>Comment Mode is turned on: {commentModeState}</div>;
> }
> ```

> [tab] React / Next.js
>
> To subscribe to changes in the comment mode, use the `onCommentModeChange()` method , as a property on `VeltCommentTool`:
>
> ```jsx theme={null}
> <VeltCommentTool onCommentModeChange={(mode) => onCommentModeChange(mode)} />
> ```
>
> API method:
>
> ```jsx theme={null}
> let subscription = commentElement.onCommentModeChange().subscribe((mode) => {
>   //mode contains the state after change
> });
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

> [tab] Other Frameworks
>
> API method:
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> let subscription = commentElement.onCommentModeChange().subscribe((mode) => {
>     //mode contains the state after change
> });
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe()
> ```

#### enableCommentTool

![](https://mintcdn.com/velt/2O8vk8YlVD4Kq-ni/images/comment-disabled.png?fit=max\&auto=format\&n=2O8vk8YlVD4Kq-ni\&q=85\&s=b95aa942ee0ed81b09a5ff2339d6c6db)

Whether the Comment Tool button is Enabled.

`Default: true`

When the Comment Tool is disabled, it can not be used to leave comments. Other ways to leave comments, such as highlighting text, will also be disabled.

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments commentTool={false} />
> ```
>
> Using API methods:
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableCommentTool();
> commentElement.disableCommentTool();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments comment-tool="false"></velt-comments>
> ```
>
> **Using API methods:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableCommentTool();
> commentElement.disableCommentTool();
> ```

#### disabled

Disables the comment tool and prevents users from adding new comments.

This is helpful when you want to temporarily or conditionally restrict comment creation while still allowing users to view existing comments.

Default: `false`

> [!NOTE]
>
> This prop disables the specific comment tool instance it is applied to; the
> `disableCommentTool()` API disables all comment tools globally.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentTool disabled={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comment-tool disabled="true"></velt-comment-tool>
> ```

#### enableChangeDetectionInCommentMode

* By default, DOM Change Detection is disabled in Comment Mode for better performance.
* You can enable it to automatically reposition comment pins when the DOM changes while in Comment Mode.

`Default: false`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments changeDetectionInCommentMode={true} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableChangeDetectionInCommentMode();
> commentElement.disableChangeDetectionInCommentMode();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments change-detection-in-comment-mode="true"></velt-comments>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableChangeDetectionInCommentMode();
> commentElement.disableChangeDetectionInCommentMode();
> ```

#### enablePersistentCommentMode

* When Persistent comment mode is enabled, you can continue leave additional comments after finishing a comment.
* When it is disabled, you will need to reclick the Comment Tool every time when you want to make a comment.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments persistentCommentMode={true}/>
> ```
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enablePersistentCommentMode();
> commentElement.disablePersistentCommentMode();
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comments persistent-comment-mode="true"></velt-comments>
> ```
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enablePersistentCommentMode();
> commentElement.disablePersistentCommentMode();
> ```

#### forceCloseAllOnEsc

* When enabled, pressing the ESC key will force close persistent comment mode even if a comment thread is currently active.
* When disabled (default), pressing ESC will only close the active comment thread but keep persistent comment mode enabled.
* This provides more control over the ESC key behavior in persistent comment mode.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments forceCloseAllOnEsc={true}/>
> ```
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableForceCloseAllOnEsc();
> commentElement.disableForceCloseAllOnEsc();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments force-close-all-on-esc="true"></velt-comments>
> ```
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableForceCloseAllOnEsc();
> commentElement.disableForceCloseAllOnEsc();
> ```

#### setPinCursorImage

You can set custom mouse cursor when the comment mode is on.
The custom cursor image must be **32 x 32 pixels**.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments pinCursorImage={BASE64_IMAGE_STRING} />
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments pin-cursor-image="BASE64_IMAGE_STRING"></velt-comments>
> ```

API Methods:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.setPinCursorImage(BASE64_IMAGE_STRING);
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setPinCursorImage(BASE64_IMAGE_STRING);
> ```

# Minimap

#### enableMinimap

![](https://mintcdn.com/velt/vGgIoGfoceFP8dEI/images/minimap.png?fit=max\&auto=format\&n=vGgIoGfoceFP8dEI\&q=85\&s=cb9c72890744a274fa255ed00db9b7ba)

* The minimap shows a bar on the edge of the screen with indicators that show where comments exist.
* Use this to enable/disable the minimap. By default it's disabled.
* It can be positioned `left` or `right`. By default, it's positioned on the right side of the screen.

**Option a. Enable using config:**

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments minimap={true} minimapPosition="left" />
> ```
>
> **API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableMinimap();
> commentElement.disableMinimap();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments minimap="true" minimap-position="left"></velt-comments>
> ```
>
> **API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableMinimap();
> commentElement.disableMinimap();
> ```

**Option b. Enable using Minimap Component:**
This offers greater flexibility to customize and position the minimap.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <div className="relative-container">
>   <VeltCommentsMinimap targetScrollableElementId="scrollableElement" position="left" />
>   <div id="scrollableElement">
>       {/* scrollable content */}
>   </div>
> </div>
>
> <style>
>   .relative-container {
>     position: relative;
>   }
>
>   #scrollableElement {
>     width: 100%;
>     height: 200px; /* or any value */
>     overflow: auto;
>   }
> </style>
>
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <div class="relative-container">
>   <velt-comments-minimap target-scrollable-element-id="scrollableElement" position="left"></velt-comments-minimap>
>   <div id="scrollableElement">
>       <!-- scrollable content -->
>   </div>
> </div>
>
> <style>
>   .relative-container {
>     position: relative;
>   }
>
>   #scrollableElement {
>     width: 100%;
>     height: 200px; /* or any value */
>     overflow: auto;
>   }
> </style>
> ```

# Inline Comments Section

#### sortBy and sortOrder

* Change the default sorting order of Comments in the Inline Comments Section.

* Params:
  * `sortBy`: The field to sort by. Currently supports `createdAt` and `lastUpdated`. Default: `lastUpdated` for multithread and `createdAt` for single thread.
  * `sortOrder`: The order to sort by. It can be `asc` or `desc`. Default: `desc` for multithread and `asc` for single thread.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltInlineCommentsSection sortBy="createdAt" sortOrder="desc" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-inline-comments-section
>   sort-by="createdAt"
>   sort-order="desc"
> ></velt-inline-comments-section>
> ```

#### multiThread

* By default [inline comment section](https://velt.dev/docs/async-collaboration/comments/setup/inline-comments.md) is multithreaded.
* You can make it single threaded by setting `multiThread` prop to `false`.
* Default: `true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltInlineCommentsSection multiThread={false} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-inline-comments-section multi-thread="false"></velt-inline-comments-section>
> ```

#### commentPlaceholder, replyPlaceholder, composerPlaceholder

* Customize placeholder text for different input fields in the inline comments section.
* Props:
  * `commentPlaceholder`: Placeholder text for the main comment input field.
  * `replyPlaceholder`: Placeholder text for the reply input field.
  * `composerPlaceholder`: Placeholder text for the composer input field.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltInlineCommentsSection
>   commentPlaceholder="ABC Placeholder"
>   replyPlaceholder="ABC Reply Placeholder"
>   composerPlaceholder="ABC Composer Placeholder"
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-inline-comments-section
>   comment-placeholder="ABC Placeholder"
>   reply-placeholder="ABC Reply Placeholder"
>   composer-placeholder="ABC Composer Placeholder"
> ></velt-inline-comments-section>
> ```

To customize placeholder text shown when **editing** an existing comment or reply, use `editPlaceholder`, `editCommentPlaceholder`, and `editReplyPlaceholder`. See [`VeltInlineCommentsSectionProps`](https://velt.dev/docs/api-reference/sdk/models/data-models#veltinlinecommentssectionprops) for details.

#### composerPosition

* Change the position of the comment composer in the inline comments section to `top` or `bottom`.
* Default: `bottom`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltInlineCommentsSection composerPosition="top" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-inline-comments-section composer-position="top"></velt-inline-comments-section>
> ```

#### context

* Pass a custom context object to the Inline Comments Section component.
* The provided context will be added to any comments created in the inline comments section, allowing you to associate custom metadata with those comments.
* Additionally, the component will filter and display only the comments that match the provided context object.
* This dual behavior makes it easy to scope comments to specific areas of your application (e.g., specific cells in a table, dashboard widgets, or data segments).

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltInlineCommentsSection
>   context={{
>     department: "marketing",
>     quarter: "Q1",
>     category: "paid-ads",
>   }}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-inline-comments-section context='{"department": "marketing", "quarter": "Q1", "category": "paid-ads"}'></velt-inline-comments-section>
> ```

#### contextOptions

* Configure the matching behavior for the context object when filtering comments.
* By default, comments must fully match all key-value pairs in the provided context.
* Set `partialMatch: true` to enable flexible matching where comments match if they contain all the specified context fields (extra fields in the comment's context are ignored).
* See [`Context` Matching](#context-matching) for detailed explanation and examples.

> [tab] React / Next.js
>
> ```jsx theme={null}
> {/* Full match (default) - comment must have exact context */}
> <VeltInlineCommentsSection 
>   context={{ department: "marketing", quarter: "Q1" }} 
> />
>
> {/* Partial match - comment matches if it contains these fields */}
>
> <VeltInlineCommentsSection 
>   context={{ department: "marketing" }} 
>   contextOptions={{ partialMatch: true }}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <!-- Full match (default) -->
> <velt-inline-comments-section 
>   context='{"department": "marketing", "quarter": "Q1"}'>
> </velt-inline-comments-section>
>
> <!-- Partial match -->
>
> <velt-inline-comments-section 
>   context='{"department": "marketing"}'
>   context-options='{"partialMatch": true}'>
> </velt-inline-comments-section>
>
> ```

#### readOnly

Control read-only mode at the component level. When enabled, users can view comments but cannot reply, edit, or add new comments in the Inline Comments Section.

The local component prop takes precedence over global settings when explicitly set.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltInlineCommentsSection
>   targetElementId="my-element"
>   readOnly={true}
> />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-inline-comments-section
>   target-element-id="my-element"
>   read-only="true">
> </velt-inline-comments-section>
> ```

# Popover Comments

#### enableDialogOnTargetElementClick

![](https://mintcdn.com/velt/gAz_vLsG-ukKamYM/gifs/hover-cell-comment.gif?s=092f6241ef57b96231d6f837b6ab9743)

Whether the comment dialog opens when target element is clicked. This is relevant only for Popover mode.

`Default: true`

> [tab] React / Next.js
>
> ```js theme={null}
> <VeltComments dialogOnTargetElementClick={true} />
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> <velt-comments dialog-on-hover="true"></velt-comments>
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableDialogOnTargetElementClick();
> commentElement.disableDialogOnTargetElementClick();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableDialogOnTargetElementClick();
> commentElement.disableDialogOnTargetElementClick();
> ```

#### enablePopoverTriangleComponent

Whether the popover triangle appears when Popover Mode is enabled.

`Default: true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltComments popoverTriangleComponent={true}/>
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comments popover-triangle-component="true"></velt-comments> 
> ```

API Method:

> [tab] React / Next.js
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enablePopoverTriangleComponent();
> commentElement.disablePopoverTriangleComponent();
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enablePopoverTriangleComponent();
> commentElement.disablePopoverTriangleComponent();
> ```

# Comment Bubble

#### annotationId

* The id of the comment annotation to show the comment bubble on.
* The bubble will be rendered only if there is a comment annotation that matches the provided `annotationId` in the current document.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentBubble annotationId="annotation-id-1" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comment-bubble annotation-id="annotation-id-1"></velt-comment-bubble>
> ```

#### targetElementId

* The DOM ID of the element where comment bubble is added.
* This binds the comment bubble to the element with the provided ID.
* The bubble will be rendered only if there is a comment annotation that was added to the element with the provided ID.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentBubble targetElementId="cell-id-1" />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comment-bubble target-element-id="cell-id-1"></velt-comment-bubble>
> ```

#### context

* The `context` object to filter which comment annotations to show the comment bubble for.
* The bubble will be rendered only if there is a comment annotation that matches the provided `context` in the current document.
* Works only with `popover` mode comments.
* Perfect for complex tables with filtering and segmentation needs.
* Set flexible comment anchoring and filtering logic at the cell level using key-value pairs.
* **Supports aggregate views:** Eg: comments added in day view can appear in week/month views automatically.
* Context commonly has combined use with [context options](#contextoptions) and the [group matched comments](#groupmatchedcomments) feature.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentTool context={{ 'key1': 'value1', 'key2': 'value2' }} />
> // Full match
> <VeltCommentBubble context={{ 'key1': 'value1', 'key2': 'value2' }} />
> // Partial match
> <VeltCommentBubble context={{ 'key1': 'value1' }} contextOptions={{ partialMatch: true }} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comment-tool context='{"key1": "value1", "key2": "value2"}'></velt-comment-tool>
>
> <!-- Full match -->
> <velt-comment-bubble context='{"key1": "value1", "key2": "value2"}'></velt-comment-bubble>
> <!-- Partial match -->
> <velt-comment-bubble context='{"key1": "value1"}' context-options='{"partialMatch": true}'></velt-comment-bubble>
> ```

#### contextOptions

* Matching behavior for the context object (default: full match, or set `partialMatch: true` for flexible matching).
* **How Partial Match Works:**
  * A comment will match if ALL provided filter criteria exist in the comment's context
  * Extra fields in the comment's context don't prevent matching
  * Missing fields in the comment's context prevent matching
  * Example: Comment has `{ day: "01", week: "01", month: "jan", product: "cheese", location: "zurich" }`
    * Filter `{ day: "01", product: "cheese" }` → ✅ matches (both fields exist in comment)
    * Filter `{ day: "01", category: "dairy" }` → ❌ no match (category doesn't exist in comment)
* **Partial Match Examples:**
  * Comment has `{ day: "01", week: "01", month: "jan", product: "cheese" }`
  * Filter with `{ day: "01", week: "01", month: "jan", product: "cheese" }` → matches (full)
  * Filter with `{ week: "01", month: "jan", product: "cheese" }` → matches (partial)
  * Filter with `{ day: "01", week: "01", month: "jan", product: "cheese", location: "zurich" }` → no match

#### groupMatchedComments

Whether to group multiple comment annotations in Comment Bubble component when multiple annotations match the provided `context` or `targetElementId`.

Default: `false`

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments groupMatchedComments={true} />
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableGroupMatchedComments();
> commentElement.disableGroupMatchedComments();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comments group-matched-comments="true"></velt-comments>
> ```
>
> **Using API:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableGroupMatchedComments();
> commentElement.disableGroupMatchedComments();
> ```

#### commentCountType

Whether to show unread or total comment replies count on Comment Bubble Component.

Type: [`CommentCountType`](https://velt.dev/docs/api-reference/sdk/models/data-models#commentcounttype)

* `total`: Shows the total number of replies. (default)
* `unread`: Shows the number of unread replies.

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentBubble commentCountType={"unread"} />
> ```

> [tab] Other Frameworks
>
> ```jsx theme={null}
> <velt-comment-bubble comment-count-type="unread">
> </velt-comment-bubble>
> ```

#### openDialog

Control whether the comment dialog opens when clicking on the comment bubble.

When disabled, clicking the bubble will not open the comment dialog. This is useful when you want to handle bubble clicks with custom logic using the [`commentBubbleClicked`](#commentbubbleclicked) event.

Default: `true`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentBubble openDialog={false} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comment-bubble open-dialog="false"></velt-comment-bubble>
> ```

#### readOnly

The `readOnly` flag prevents users from replying or editing existing comments in the target bubble while still displaying them.

This is useful when you want to display comments in a read-only mode where users can view but not modify or respond to comments.

Default: `false`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentBubble readOnly={true} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comment-bubble read-only="true"></velt-comment-bubble>
> ```

# Video Timeline Comments

#### setTotalMediaLength

Set the total length of media (in frames or seconds) for the timeline.

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltCommentPlayerTimeline totalMediaLength={120} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.setTotalMediaLength(120);
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```html theme={null}
> <velt-comment-player-timeline total-media-length="120"></velt-comment-player-timeline>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.setTotalMediaLength(120);
> ```

#### offset

* Allows comment bubbles to be positioned relative to both parent and child video clips by specifying an offset value.
* Default: `0`

> [tab] React / Next.js
>
> ```jsx theme={null}
> <VeltCommentPlayerTimeline offset={10} />
> ```

> [tab] Other Frameworks
>
> ```html theme={null}
> <velt-comment-player-timeline offset="10"></velt-comment-player-timeline>
> ```

# Comment Pin

#### enableBubbleOnPin

Show a Comment Bubble when user hovers or clicks on the Comment Pin vs showing the Comment Dialog.
The comment dialog will open only on clicking the comment bubble.

`Default: 'false'`

> [tab] React / Next.js with Hooks
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments bubbleOnPin={true} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = useCommentUtils();
> commentElement.enableBubbleOnPin();
> commentElement.disableBubbleOnPin();
> ```

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments bubbleOnPin={true} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> commentElement.enableBubbleOnPin();
> commentElement.disableBubbleOnPin();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```jsx theme={null}
> <velt-comments bubble-on-pin="true">
> </velt-comments>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> commentElement.enableBubbleOnPin();
> commentElement.disableBubbleOnPin();
> ```

#### enableBubbleOnPinHover

Show a Comment Bubble when user hovers on the Comment Pin vs clicks on it.

`Default: 'true'`

> [tab] React / Next.js with Hooks
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments bubbleOnPin={true} bubbleOnPinHover={false} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = useCommentUtils();
>
> // To enable/disable showing bubble on pin
> commentElement.enableBubbleOnPin();
> commentElement.disableBubbleOnPin();
>
> // To enable/disable showing bubble on hover
> commentElement.enableBubbleOnPinHover();
> commentElement.disableBubbleOnPinHover();
>
> ```

> [tab] React / Next.js
>
> **Using Props:**
>
> ```jsx theme={null}
> <VeltComments bubbleOnPin={true} bubbleOnPinHover={false} />
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = client.getCommentElement();
> // To enable/disable showing bubble on pin
> commentElement.enableBubbleOnPin();
> commentElement.disableBubbleOnPin();
>
> // To enable/disable showing bubble on hover
> commentElement.enableBubbleOnPinHover();
> commentElement.disableBubbleOnPinHover();
> ```

> [tab] Other Frameworks
>
> **Using Props:**
>
> ```jsx theme={null}
> <velt-comments bubble-on-pin="true" bubble-on-pin-hover="false"></velt-comments>
> ```
>
> **Using API Method:**
>
> ```jsx theme={null}
> const commentElement = Velt.getCommentElement();
> // To enable/disable showing bubble on pin
> commentElement.enableBubbleOnPin();
> commentElement.disableBubbleOnPin();
>
> // To enable/disable showing bubble on hover
> commentElement.enableBubbleOnPinHover();
> commentElement.disableBubbleOnPinHover();
>
> ```

# Legacy Methods

#### onCommentAdd

> [tab] React / Next.js
>
> Using Props:
>
> ```js theme={null}
> <VeltComments onCommentAdd={(event) => yourMethod(event)} />
>
> const yourMethod = (event) => {
>   event?.addContext({ customKey: 'customValue' });
> }
> ```
>
> Using Hooks:
>
> ```jsx theme={null}
> import { useCommentAddHandler } from "@veltdev/react";
>
> export default function YourDocument() {
>   const commentAddEvent = useCommentAddHandler();
>
>   useEffect(() => {
>     console.log("commentAddEvent", commentAddEvent);
>   }, [commentAddEvent]);
>
>   return <div></div>;
> }
> ```
>
> Using API:
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
>
> commentElement.onCommentAdd().subscribe((event) => {
>   console.log("commentAddEvent", event);
> });
> ```

> [tab] Other Frameworks
>
> Using Event listener:
>
> ```js theme={null}
> const veltCommentsTag = document.querySelector("velt-comments");
>
> veltCommentsTag?.addEventListener("onCommentAdd", (event) => {
>   console.log("*** onCommentAdd ***");
>   console.log(event.detail);
>   event.detail?.addContext({ customKey: "customValue" });
> });
> ```
>
> Using API method:
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
>
> commentElement.onCommentAdd().subscribe((event) => {
>   event?.addContext({ customKey: "customValue" });
> });
> ```

**onCommentAdd Event Data Schema**

| Field Name | Type | Description |
| - | - | - |
| addContext | Function | Use this to set custom data on the comment |
| annotation | CommentAnnotation | The annotation that is associated with the comment that was updated |
| documentId | string | The document ID where the comment was added |
| location | Object | The location where the comment was added |
| targetAnnotationId | string | The id of the target annotation |

#### onCommentUpdate

> [tab] React / Next.js
>
> Using Props:
>
> ```js theme={null}
> <VeltComments onCommentUpdate={(event) => yourMethod(event)} />;
>
> const yourMethod = (event) => {
>   console.log("commentUpdateEvent", event);
> };
> ```
>
> Using Hooks:
>
> ```jsx theme={null}
> import { useCommentUpdateHandler } from "@veltdev/react";
>
> export default function YourDocument() {
>   const commentUpdateEvent = useCommentUpdateHandler();
>   useEffect(() => {
>     console.log("commentUpdateEvent", commentUpdateEvent);
>   }, [commentUpdateEvent]);
>
>   return <div></div>;
> }
> ```
>
> Using API:
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
>
> commentElement.onCommentUpdate().subscribe((event) => {
>   console.log("commentUpdateEvent", event);
> });
> ```

> [tab] Other Frameworks
>
> Using Event Listener:
>
> ```js theme={null}
> const veltCommentsTag = document.querySelector('velt-comments');
>
> veltCommentsTag?.addEventListener('onCommentUpdate', (event) => {
> console.log('**_ onCommentUpdate _**');
> console.log(event.detail);
> });
>
> ```
>
> Using API method:
>
> ```js theme={null}
> const commentElement = Velt.getCommentElement();
>
> commentElement.onCommentUpdate().subscribe((event) => {
>   console.log('commentUpdateEvent', event);
> });
> ```

**onCommentUpdate Event Data Schema**

| Field Name | Type | Description |
| - | - | - |
| annotation | CommentAnnotation | The annotation that is associated with the comment that was updated |
| type | string | The type of comment that was updated |
| targetAnnotationId | string | The ID of the target annotation that contains the comment that was updated |
| targetCommentId | number | The ID of the target comment that was updated |
| updateContext | Function | Use this to update the custom metadata on the comment annotation. |

#### getAllCommentAnnotations

* Get all comment annotations for a given document and location.
* By default, it will return data for the current `documentId` and `location`.
* Params (optional):
  * `documentId`: string; it will return all comments in the given `documentId`.
  * `location`: Object; it will return all comments in the given `location`.

> [tab] React / Next.js
>
> **Using Hooks:**
>
> ```jsx theme={null}
> const commentAnnotations = useCommentAnnotations();
> useEffect(() => {
>   if (commentAnnotations) {
>     console.log("commentAnnotations", commentAnnotations);
>   }
> }, [commentAnnotations]);
> ```
>
> **Using API:**
>
> ```js theme={null}
> const commentElement = client.getCommentElement();
> let subscription = commentElement
>   .getAllCommentAnnotations()
>   .subscribe((comments) => {
>     console.log("commentAnnotations", comments);
>   });
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe();
> ```

> [tab] Other Frameworks
>
> ```js theme={null}
> if (Velt) {
>   const commentElement = Velt.getCommentElement();
>   let subscription = commentElement.getAllCommentAnnotations().subscribe((comments) => {
>     // Do something with comments
>   });
> }
> ```
>
> To unsubscribe from the subscription:
>
> ```jsx theme={null}
> subscription?.unsubscribe()
> ```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.