# Rewriter Source: https://docs.velt.dev/ai-copilot/design/overview Let AI suggest improvements to your website text ``` #### data-velt-pdf-viewer ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/pdf-comments.png) 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
``` #### 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` **Using Props:** ```jsx ``` **Using API:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableSvgAsImg(); commentElement.disableSvgAsImg(); ``` **Using Props:** ```html ``` **Using API:** ```html const commentElement = client.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` **Using Props:** ```jsx ``` **Using API Method:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableHotkey(); commentElement.disableHotkey(); ``` **Using Props:** ```html ``` **Using API Method:** ```jsx 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`. **Using Props:** ```jsx ``` **Using API Method:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableEnterKeyToSubmit(); commentElement.disableEnterKeyToSubmit(); ``` **Using Props:** ```jsx ``` **Using API Method:** ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableEnterKeyToSubmit(); commentElement.disableEnterKeyToSubmit(); ``` #### enableDeleteOnBackspace * Use this to enable or disable deleting comments when backpsace key is pressed. Default: `enabled` **Using Props:** ```jsx ``` **Using API:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableDeleteOnBackspace(); commentElement.disableDeleteOnBackspace(); ``` **Using Props:** ```jsx ``` **Using API:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableDeleteOnBackspace(); commentElement.disableDeleteOnBackspace(); ``` # Moderation #### enableModeratorMode ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/moderator-mode.png) 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. ```js ``` ```js ``` API Method: ```jsx const commentElement = client.getCommentElement(); commentElement.enableModeratorMode(); commentElement.disableModeratorMode(); ``` ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableModeratorMode(); commentElement.disableModeratorMode(); ``` #### enableResolveStatusAccessAdminOnly * Restrict the resolve action to admin users and the comment author only. **Using props:** ```jsx ``` **Using API:** ```javascript const commentElement = client.getCommentElement(); // To enable resolve status access admin only commentElement.enableResolveStatusAccessAdminOnly(); // To disable resolve status access admin only commentElement.disableResolveStatusAccessAdminOnly(); ``` **Using props:** ```html ``` **Using API:** ```javascript 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](/api-reference/sdk/models/api-request-objects#approvecommentannotationrequest) * Returns: [ApproveCommentAnnotationEvent](/api-reference/sdk/models/api-event-objects#approvecommentannotationevent) ```jsx 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); ``` ```js const approveCommentAnnotationRequest = { annotationId: 'ANNOTATION_ID' }; const commentElement = Velt.getCommentElement(); const approveCommentAnnotationEvent = await commentElement.approveCommentAnnotation(approveCommentAnnotationRequest); ``` #### acceptCommentAnnotation * Accepts a comment annotation in suggestion mode * Params: [AcceptCommentAnnotationRequest](/api-reference/sdk/models/api-request-objects#acceptcommentannotationrequest) * Returns: [AcceptCommentAnnotationEvent](/api-reference/sdk/models/api-event-objects#acceptcommentannotationevent) ```jsx const acceptCommentAnnotationRequest = { annotationId: 'ANNOTATION_ID' }; // Hook const { acceptCommentAnnotation } = useAcceptCommentAnnotation(); const acceptCommentAnnotationEventData = await acceptCommentAnnotation(acceptCommentAnnotationRequest); // API Method const commentElement = client.getCommentElement(); const acceptCommentAnnotationEventData = await commentElement.acceptCommentAnnotation(acceptCommentAnnotationRequest); ``` ```js const acceptCommentAnnotationRequest = { annotationId: 'ANNOTATION_ID' }; const commentElement = Velt.getCommentElement(); const acceptCommentAnnotationEventData = await commentElement.acceptCommentAnnotation(acceptCommentAnnotationRequest); ``` #### rejectCommentAnnotation * Rejects a comment annotation in suggestion mode * Params: [RejectCommentAnnotationRequest](/api-reference/sdk/models/api-request-objects#rejectcommentannotationrequest) * Returns: [RejectCommentAnnotationEvent](/api-reference/sdk/models/api-event-objects#rejectcommentannotationevent) ```jsx const rejectCommentAnnotationRequest = { annotationId: 'ANNOTATION_ID' }; // Hook const { rejectCommentAnnotation } = useRejectCommentAnnotation(); const rejectCommentAnnotationEventData = await rejectCommentAnnotation(rejectCommentAnnotationRequest); // API Method const commentElement = client.getCommentElement(); const rejectCommentAnnotationEventData = await commentElement.rejectCommentAnnotation(rejectCommentAnnotationRequest); ``` ```js const rejectCommentAnnotationRequest = { annotationId: 'ANNOTATION_ID' }; const commentElement = Velt.getCommentElement(); const rejectCommentAnnotationEventData = await commentElement.rejectCommentAnnotation(rejectCommentAnnotationRequest); ``` #### enableSuggestionMode ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/accept-reject.png) Whether to enable suggestion mode to accept or reject comments. `Default: false` To accept comments, set the `suggestionMode` attribute to `true`. ```js ``` To accept comments, set the `suggestion-mode` attribute to `true`. ```js ``` API Method: ```jsx const commentElement = client.getCommentElement(); commentElement.enableSuggestionMode(); commentElement.disableSuggestionMode(); ``` ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableSuggestionMode(); commentElement.disableSuggestionMode(); ``` #### updateAccess * Updates access permissions for a comment annotation * Params: [UpdateAccessRequest](/api-reference/sdk/models/api-request-objects#updateaccessrequest) * Returns: [UpdateAccessEvent](/api-reference/sdk/models/api-event-objects#updateaccessevent) ```jsx const updateAccessRequest = { annotationId: 'ANNOTATION_ID', accessMode: 'private'; }; // Hook const { updateAccess } = useUpdateAccess(); const updateAccessEvent = await updateAccess(updateAccessRequest); // API Method const commentElement = client.getCommentElement(); const updateAccessEvent = await commentElement.updateAccess(updateAccessRequest); ``` ```js const updateAccessRequest = { annotationId: 'ANNOTATION_ID', accessMode: 'private'; } }; const commentElement = Velt.getCommentElement(); const updateAccessEvent = await commentElement.updateAccess(updateAccessRequest); ``` #### enablePrivateComments ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/private-comment.png) * Private comment mode enables admin users to add comments that are only visible to other admin users. * Use this to enable or disable private comment mode. Default: `false` To enable private comment mode, set the `privateCommentMode` attribute to `true`: ```html ``` To enable private comment mode, set the `private-comment-mode` attribute to `true`: ```html ``` API Methods: API to enable/disable private comment mode: ```jsx const commentElement = client.getCommentElement(); // To enable private comment mode commentElement.enablePrivateCommentMode(); // To disable private comment mode commentElement.disablePrivateCommentMode(); ``` ```jsx const commentElement = Velt.getCommentElement(); // To enable private comment mode commentElement.enablePrivateCommentMode(); // To disable private comment mode commentElement.disablePrivateCommentMode(); ``` #### 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` Using Props: ```jsx ``` Using API: ```js const commentElement = client.getCommentElement(); commentElement.enableReadOnly(); commentElement.disableReadOnly(); ``` Using Props: ```html ``` Using API: ```js 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` **Using Props:** ```jsx ``` **Using API:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableSeenByUsers(); commentElement.disableSeenByUsers(); ``` **Using Props:** ```html ``` **Using API:** ```javascript 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://mintlify.s3.us-west-1.amazonaws.com/velt/images/unread-compare.png) ```jsx ``` ```jsx ``` API Method: ```jsx const commentElement = client.getCommentElement(); commentElement.setUnreadIndicatorMode("verbose"); // use badge with text UNREAD commentElement.setUnreadIndicatorMode("minimal"); // use small red dot indicator ``` ```jsx 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://mintlify.s3.us-west-1.amazonaws.com/velt/images/enable-disable-area-comments.png) **Using Props:** ```jsx ``` **Using API Method:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableAreaComment(); commentElement.disableAreaComment(); ``` **Using Props:** ```jsx ``` Using API Method: ```jsx const commentElement = client.getCommentElement(); commentElement.enableAreaComment(); commentElement.disableAreaComment(); ``` #### enableInboxMode For a complete setup guide for Inbox mode, [read here](/async-collaboration/comments/setup/inbox). Whether Inbox Mode is enabled. Default: `false` **Using Props:** ```jsx ``` **Using API:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableInboxMode(); commentElement.disableInboxMode(); ``` **Using Props:** ```html ``` **Using API:** ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableInboxMode(); commentElement.disableInboxMode(); ``` #### enablePopoverMode For a complete setup guide for Popover mode, [read here](/async-collaboration/comments/setup/popover). Whether Popover Mode is enabled. Default: `false` ```jsx ``` **Using API:** ```jsx const commentElement = client.getCommentElement(); commentElement.enablePopoverMode(); commentElement.disablePopoverMode(); ``` ```jsx ``` **Using API:** ```jsx const commentElement = Velt.getCommentElement(); commentElement.enablePopoverMode(); commentElement.disablePopoverMode(); ``` #### enableStreamMode For a complete setup guide for Stream mode, [read here](/async-collaboration/comments/setup/stream). Whether Stream Mode is enabled. Default: `false` ```jsx ``` **Using API:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableStreamMode(); commentElement.disableStreamMode(); ``` ```jsx ``` **Using API:** ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableStreamMode(); commentElement.disableStreamMode(); ``` #### enableTextMode For a complete setup guide for Text mode, [read here](/async-collaboration/comments/setup/text). Whether Text Mode is enabled. Default: `true` ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/text-comment.png) **Using Props:** ```jsx ``` **Using API:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableTextComments(); commentElement.disableTextComments(); ``` **Using Props:** ```html ``` **Using API:** ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableTextComments(); commentElement.disableTextComments(); ``` #### enableInlineCommentMode ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/text-comment-opened.png) 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` ```jsx ``` ```jsx const commentElement = client.getCommentElement(); commentElement.enableInlineCommentMode(); commentElement.disableInlineCommentMode(); ``` ```jsx ``` ```jsx 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](/ui-customization/features/async/comments/multithread-comment-dialog). * Default: `false` ```jsx ``` ```html ``` # 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. ```jsx // For popover comments ``` ```html ``` #### enableCommentMode ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/comment-mode-on-off.png) 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 programatically turn on the commenting mode. ```jsx const commentElement = client.getCommentElement(); commentElement.enableCommentMode(); commentElement.disableCommentMode(); ``` ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableCommentMode(); commentElement.disableCommentMode(); ``` #### onCommentModeChange ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/onCommentModeChange.png) The comment mode is toggled on and off when you click on the Comment Tool. 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 import { useCommentModeState } from '@veltdev/react'; export default function YourDocument() { let commentModeState = useCommentModeState() return (
Comment Mode is turned on: {commentModeState}
) } ```
To subscribe to changes in the comment mode, use the `onCommentModeChange()` method , as a property on `VeltCommentTool`: ```jsx onCommentModeChange(mode)} /> ``` API method: ```jsx let subscription = commentElement.onCommentModeChange().subscribe((mode) => { //mode contains the state after change }); ``` To unsubscribe from the subscription: ```jsx subscription?.unsubscribe() ``` API method: ```jsx const commentElement = Velt.getCommentElement(); let subscription = commentElement.onCommentModeChange().subscribe((mode) => { //mode contains the state after change }); ``` To unsubscribe from the subscription: ```jsx subscription?.unsubscribe() ```
#### enableCommentTool ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/comment-disabled.png) 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. **Using Props:** ```jsx ``` Using API methods: ```jsx const commentElement = client.getCommentElement(); commentElement.enableCommentTool(); commentElement.disableCommentTool(); ``` **Using Props:** ```html ``` **Using API methods:** ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableCommentTool(); commentElement.disableCommentTool(); ``` #### 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` **Using Props:** ```jsx ``` **Using API Method:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableChangeDetectionInCommentMode(); commentElement.disableChangeDetectionInCommentMode(); ``` **Using Props:** ```html ``` **Using API Method:** ```jsx 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` ```jsx ``` ```jsx const commentElement = client.getCommentElement(); commentElement.enablePersistentCommentMode(); commentElement.disablePersistentCommentMode(); ``` ```jsx ``` ```jsx const commentElement = Velt.getCommentElement(); commentElement.enablePersistentCommentMode(); commentElement.disablePersistentCommentMode(); ``` #### setPinCursorImage You can set custom mouse cursor when the comment mode is on. The custom cursor image must be **32 x 32 pixels**. ```jsx ``` ```jsx ``` API Methods: ```jsx const commentElement = client.getCommentElement(); commentElement.setPinCursorImage(BASE64_IMAGE_STRING); ``` ```jsx const commentElement = Velt.getCommentElement(); commentElement.setPinCursorImage(BASE64_IMAGE_STRING); ``` # Minimap #### enableMinimap ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/minimap.png) * 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:** ```jsx ``` **API Method:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableMinimap(); commentElement.disableMinimap(); ``` ```jsx ``` **API Method:** ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableMinimap(); commentElement.disableMinimap(); ``` **Option b. Enable using Minimap Component:** This offers greater flexibility to customize and position the minimap. ```jsx
{/* scrollable content */}
```
```jsx
```
# Inline Comments #### 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. ```jsx ``` ```html ``` #### multiThread * By default [inline comment section](/async-collaboration/comments/setup/inline-comments) is multithreaded. * You can make it single threaded by setting `multiThread` prop to `false`. * Default: `true` ```jsx ``` ```html ``` #### composerPosition * Change the position of the comment composer in the inline comments section to `top` or `bottom`. * Default: `bottom` ```jsx ``` ```html ``` # Popover Comments #### enableDialogOnTargetElementClick ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/gifs/hover-cell-comment.gif) Whether the comment dialog opens when target element is clicked. This is relevant only for Popover mode. `Default: true` ```js ``` ```js ``` API Method: ```jsx const commentElement = client.getCommentElement(); commentElement.enableDialogOnTargetElementClick(); commentElement.disableDialogOnTargetElementClick(); ``` ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableDialogOnTargetElementClick(); commentElement.disableDialogOnTargetElementClick(); ``` #### enablePopoverTriangleComponent Whether the popover triangle appears when Popover Mode is enabled. `Default: true` ```jsx ``` ```jsx ``` API Method: ```jsx const commentElement = client.getCommentElement(); commentElement.enablePopoverTriangleComponent(); commentElement.disablePopoverTriangleComponent(); ``` ```jsx 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. ```jsx ``` ```html ``` #### 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. ```jsx ``` ```html ``` #### 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. ```jsx // Full match // Partial match ``` ```html ``` #### 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 #### commentCountType Whether to show unread or total comment replies count on Comment Bubble Component. * `total`: Shows the total number of replies. (default) * `unread`: Shows the number of unread replies. ```jsx ``` ```jsx ``` #### groupMatchedComments Whether to group multiple comment annotations in Comment Bubble component when multiple annotations match the provided `context` or `targetElementId`. Default: `false` **Using Props:** ```jsx ``` **Using API:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableGroupMatchedComments(); commentElement.disableGroupMatchedComments(); ``` **Using Props:** ```html ``` **Using API:** ```jsx const commentElement = Velt.getCommentElement(); commentElement.enableGroupMatchedComments(); commentElement.disableGroupMatchedComments(); ``` # Video Timeline Comments #### setTotalMediaLength Set the total length of media (in frames or seconds) for the timeline. **Using Props:** ```jsx ``` **Using API Method:** ```jsx const commentElement = client.getCommentElement(); commentElement.setTotalMediaLength(120); ``` **Using Props:** ```html ``` **Using API Method:** ```jsx 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` ```jsx ``` ```html ``` # 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'` **Using Props:** ```jsx ``` **Using API Method:** ```jsx const commentElement = useCommentUtils(); commentElement.enableBubbleOnPin(); commentElement.disableBubbleOnPin(); ``` **Using Props:** ```jsx ``` **Using API Method:** ```jsx const commentElement = client.getCommentElement(); commentElement.enableBubbleOnPin(); commentElement.disableBubbleOnPin(); ``` **Using Props:** ```jsx ``` **Using API Method:** ```jsx 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'` **Using Props:** ```jsx ``` **Using API Method:** ```jsx 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(); ``` **Using Props:** ```jsx ``` **Using API Method:** ```jsx 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(); ``` **Using Props:** ```jsx ``` **Using API Method:** ```jsx 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 Using Props: ```js yourMethod(event)} /> const yourMethod = (event) => { event?.addContext({ customKey: 'customValue' }); } ``` Using Hooks: ```jsx import { useCommentAddHandler} from '@veltdev/react'; export default function YourDocument() { const commentAddEvent = useCommentAddHandler(); useEffect(() => { console.log('commentAddEvent', commentAddEvent); }, [commentAddEvent]); return (
) } ``` Using API: ```js const commentElement = client.getCommentElement(); commentElement.onCommentAdd().subscribe((event) => { console.log('commentAddEvent', event); }); ```
Using Event listener: ```js 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 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 Using Props: ```js yourMethod(event)} /> const yourMethod = (event) => { console.log('commentUpdateEvent', event); } ``` Using Hooks: ```jsx import { useCommentUpdateHandler} from '@veltdev/react'; export default function YourDocument() { const commentUpdateEvent = useCommentUpdateHandler(); useEffect(() => { console.log('commentUpdateEvent', commentUpdateEvent); }, [commentUpdateEvent]); return (
) } ``` Using API: ```js const commentElement = client.getCommentElement(); commentElement.onCommentUpdate().subscribe((event) => { console.log('commentUpdateEvent', event); }); ```
Using Event Listener: ```js const veltCommentsTag = document.querySelector('velt-comments'); veltCommentsTag?.addEventListener('onCommentUpdate', (event) => { console.log('*** onCommentUpdate ***'); console.log(event.detail); }); ``` Using API method: ```js 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`. **Using Hooks:** ```jsx const commentAnnotations = useCommentAnnotations(); useEffect(() => { if (commentAnnotations) { console.log('commentAnnotations', commentAnnotations); } }, [commentAnnotations]); ``` **Using API:** ```js const commentElement = client.getCommentElement(); let subscription = commentElement.getAllCommentAnnotations().subscribe((comments) => { console.log('commentAnnotations', comments); }); ``` To unsubscribe from the subscription: ```jsx subscription?.unsubscribe() ``` ```js if (Velt) { const commentElement = Velt.getCommentElement(); let subscription = commentElement.getAllCommentAnnotations().subscribe((comments) => { // Do something with comments }); } ``` To unsubscribe from the subscription: ```jsx subscription?.unsubscribe() ``` # Notifications Source: https://docs.velt.dev/async-collaboration/comments/notifications There are several options to send notifications to your users. There are three ways to send notifications to your users: Add notifications component within your app. Send email notifications to your users. Send notifications to other channels like Slack. ## In-app notifications Add notifications component within your app. Learn more about [In-app notifications](/async-collaboration/notifications/overview). ## Email notifications You can enable email notifications to send out emails whenever you `@mention` a user in the Comments feature or when another user replies to your comment. There are two ways to trigger email notifications: Webhooks and SendGrid. ### Webhooks for non-SendGrid services To learn how to trigger email notifications via Webhooks please refer [here](/webhooks/basic). ### SendGrid Integration To enable Email Notifications, go to the Configurations -> Email Service in the Velt Console, or [click here](https://console.velt.dev/dashboard/config/email). For SendGrid integration, provide the following details: * SendGrid API Key * SendGrid Email Template ID for Comments feature * 'From' Email Address The 'From' Email Address needs to be whitelisted from your SendGrid account or else it will not work. #### Email Template Data The following fields are sent to Sendgrid: | Field | Type | Description | | -------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | firstComment | [Comment](/api-reference/sdk/models/data-models#comment) | First message in the thread. **Only Contains** `commentId`, `commentText` and `from` properties derived from Comment class. | | latestComment | [Comment](/api-reference/sdk/models/data-models#comment) | Latest message in the thread that prompted the email. **Only Contains** `commentId`, `commentText` and `from` properties derived from Comment class. | | prevComment | [Comment](/api-reference/sdk/models/data-models#comment) | Previous message to the latestMessage. **Only Contains** `commentId`, `commentText` and `from` properties derived from Comment class. | | commentsCount | string | Total number of comments in the comment annotation | | commentsCountMoreThanThree | string | Total number of remaining comments in the comment annotation beyond the three that this payload contains | | fromUser | [User](/api-reference/sdk/models/data-models#user) | Action user's object | | commentAnnotation | [CommentAnnotation](/api-reference/sdk/models/data-models#commentannotation) | The comment annotation object without the `comments` field | | actionType | string | The action that resulted in the notification. You can find the list of action types [here](/webhooks/basic#list-of-action-types) | | documentMetadata | [DocumentMetadata](/api-reference/sdk/models/data-models#documentmetadata) | The document metadata object | These are the older fields that will be deprecated soon. These are already contained in the fields above: | Field | Type | Description | | --------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | message | string | the message of the email | | messageFromName | string | the name of whoever wrote the message that the email is referencing. If name is not found then it will contain the email. | | name | string | the name of the person who performed the action that triggered the email. If name is not found then it will contain the email. Sometimes a notification can be triggered without a message. For those cases, you can use this. | | fromEmail | string | email address of the user who performed the action | | photoUrl | string | avatar URL of user | | pageUrl | string | url of the page the comment is on | | pageTitle | string | title of the web page | | deviceInfo | Object | contains browser, OS and device info | | subject | string | subject of the email | #### Sample Payload sent to SendGrid ```json expandable lines { "fromName": "Tony via ", "fromEmail": "noreply@example.com", "replyTo": "tony@example.com", "templateId": "d-60ba77a7a42a4e55803487b40982b499", "toEmail": "jess@example.com", "properties": { "message": "@Jess", "messageFromName": "Tony", "name": "Tony", "fromName": "Tony via ", "fromEmail": "tony@trysnippyly.com", "photoUrl": "PHOTO_URL", "pageUrl": "https://example.com/?scommentId=4Fnt7zTvPv9ggE7OOTVG", "pageTitle": "Example Title", "deviceInfo": {...}, "subject": "added you to a comment on Example Title", "actionType": "newlyAdded", "fromUser": {...}, // User Object "commentAnnotation": {...}, // CommentAnnotation Object "commentsCount": 1, "firstComment": {...}, // Comment Object "prevComment": {...}, // Comment Object "commentsCountMoreThanThree": 0, "latestComment": {...}, // Comment Object "documentMetadata": {...} // DocumentMetadata Object } } ``` #### Download Sample Email Template ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/email-template.png) We have provided this sample HTML email template you can use for your SendGrid email template: [Download Link](https://firebasestorage.googleapis.com/v0/b/snippyly.appspot.com/o/external%2Femail-template.html?alt=media\&token=16a17614-70ca-464c-b6f4-2b2b097b0007) ```html expandable lines Email Template
@here testing here functionality
    
``` ## Webhooks Send notifications to other channels like Slack. Learn more about [Webhooks](/webhooks/basic). # Comments Source: https://docs.velt.dev/async-collaboration/comments/overview Your users can add comments in context to ask questions, leave feedback, report bugs etc. We handle all complexity to ensure the comments are robust against content changes. We support many types of comment UX patterns as illustrated below. With `Freestyle` comments, you can pin `Comments` on any elements on the page or draw area comments. [Open in larger window](https://demo-examples.vercel.app/async/comments/area-comments?background=000\&theme=dark) */} */} Check out this guide on [how to set up Velt with your existing app](/get-started/setup/install) ```jsx App.js import { VeltProvider, VeltComments, VeltPresence } from '@veltdev/react'; import YourAuthComponent from './YourAuthComponent'; import YourDocument from './YourDocument'; export default function App() { return ( ); } ``` ```jsx YourAuthComponent.js import { useIdentify} from "@veltdev/react"; import { useState } from "react"; export default function YourAuthComponent() { const userService = () => { return { uid: "user1", displayName: "User 1", email: "user1@velt.dev", photoURL: "https://i.pravatar.cc/301" }; }; // Fetch user data from user service let yourAuthenticatedUser = userService(); const { uid, displayName, email, photoURL } = yourAuthenticatedUser; // Create the Velt user object let veltUser = { userId: uid, name: displayName, email: email, photoUrl: photoURL, }; //identify Velt user useIdentify(veltUser) let [user,setUser] = useState(veltUser) return
User: {user?.userId}
; } ``` ```jsx YourDocument.js import { useSetDocumentId, VeltCommentTool, VeltPresence } from '@veltdev/react'; import { useEffect, useState } from 'react'; export default function YourDocument() { useSetDocumentId('my-document-id') return (
); } ```
# Advanced Setup Options Source: https://docs.velt.dev/get-started/setup/advanced ## Advanced Set Up options This section includes a list of optional advanced set up options. ## Location Users logged into the same **Document** ID can see each other's `Presence`, `Cursors`, `Comments` etc. However, if you want to add another layer of categorization to organize users together, you can use **Location**. If a **Document** is like a house, a **Location** is like a room within the house. To learn more about `Locations`, check out its dedicated section [here](/key-concepts/overview#locations). ## Contacts When you reply to a comment, you can `@mention` other teammates that are added to a `User's Contacts List`. To learn more about creating a `User's Contacts List`, [read here](/key-concepts/users/contact-list). ## Detect if Velt SDK is initialized This returns true when both the Velt User and Document are initialized: ```jsx let subscription = client.getVeltInitState().subscribe((veltInitState: boolean | undefined) => { console.log('Velt Init State:', veltInitState); }); ``` To unsubscribe from the subscription: ```jsx subscription?.unsubscribe() ``` You can also the use `useVeltInitState()` hook: ```jsx import { useVeltInitState } from '@veltdev/react'; function YourComponent() { const veltInitState = useVeltInitState(); useEffect(() => { console.log('Velt Init State:', veltInitState); if (veltInitState) { // Velt state is initialized, so user can perform any action here } }, [veltInitState]); } ``` ## Advanced Set Up options This section includes a list of optional advanced set up options. ## Location Users logged into the same **Document** ID can see each other's `Presence`, `Cursors`, `Comments` etc. However, if you want to add another layer of categorization to organize users together, you can use **Location**. If a **Document** is like a house, a **Location** is like a room within the house. To learn more about `Locations`, check out its dedicated section [here](/key-concepts/overview#locations). ## Contacts When you reply to a comment, you can `@mention` other teammates that are added to a `User's Contacts List`. To learn more about creating a `User's Contacts List`, [read here](/key-concepts/users/contact-list). ## Detect if Velt SDK is initialized This returns true when both the Velt User and Document are initialized: ```jsx let subscription = client.getVeltInitState().subscribe((veltInitState: boolean | undefined) => { console.log('Velt Init State:', veltInitState); }); ``` To unsubscribe from the subscription: ```jsx subscription?.unsubscribe() ``` ## Advanced Set Up options This section includes a list of optional advanced set up options. ## Location Users logged into the same **Document** ID can see each other's `Presence`, `Cursors`, `Comments` etc. However, if you want to add another layer of categorization to organize users together, you can use **Location**. If a **Document** is like a house, a **Location** is like a room within the house. To learn more about `Locations`, check out its dedicated section [here](/key-concepts/overview#locations). ## Contacts When you reply to a comment, you can `@mention` other teammates that are added to a `User's Contacts List`. To learn more about creating a `User's Contacts List`, [read here](/key-concepts/users/contact-list). ## Detect if Velt SDK is initialized This returns true when both the Velt User and Document are initialized: ```jsx let subscription = Velt.getVeltInitState().subscribe((veltInitState: boolean | undefined) => { console.log('Velt Init State:', veltInitState); }); ``` To unsubscribe from the subscription: ```jsx subscription?.unsubscribe() ``` ## Advanced Set Up options This section includes a list of optional advanced set up options. ## Location Users logged into the same **Document** ID can see each other's `Presence`, `Cursors`, `Comments` etc. However, if you want to add another layer of categorization to organize users together, you can use **Location**. If a **Document** is like a house, a **Location** is like a room within the house. To learn more about `Locations`, check out its dedicated section [here](/key-concepts/overview#locations). ## Contacts When you reply to a comment, you can `@mention` other teammates that are added to a `User's Contacts List`. To learn more about creating a `User's Contacts List`, [read here](/key-concepts/users/contact-list). ## Detect if Velt SDK is initialized This returns true when both the Velt User and Document are initialized: ```jsx let subscription = this.client.getVeltInitState().subscribe((veltInitState: boolean | undefined) => { console.log('Velt Init State:', veltInitState); }); ``` To unsubscribe from the subscription: ```jsx subscription?.unsubscribe() ``` ## Advanced Set Up options This section includes a list of optional advanced set up options. ## Location Users logged into the same **Document** ID can see each other's `Presence`, `Cursors`, `Comments` etc. However, if you want to add another layer of categorization to organize users together, you can use **Location**. If a **Document** is like a house, a **Location** is like a room within the house. To learn more about `Locations`, check out its dedicated section [here](/key-concepts/overview#locations). ## Contacts When you reply to a comment, you can `@mention` other teammates that are added to a `User's Contacts List`. To learn more about creating a `User's Contacts List`, [read here](/key-concepts/users/contact-list). ## Detect if Velt SDK is initialized This returns true when both the Velt User and Document are initialized: ```jsx let subscription = client.getVeltInitState().subscribe((veltInitState: boolean | undefined) => { console.log('Velt Init State:', veltInitState); }); ``` To unsubscribe from the subscription: ```jsx subscription?.unsubscribe() ``` # 2. Authenticate Source: https://docs.velt.dev/get-started/setup/authenticate Autheticate your logged in users with the SDK. It is critical that you do the following steps within a child component and not within the same root component where you placed the VeltProvider. Realistically, these steps should be done inside your component that handles authentication. Import the `useIdentify` hook. ```js import { useIdentify } from '@veltdev/react' ``` Create a Velt `User` object. ```js // Fetch the relevant user info from `yourAuthenticatedUser` const { uid, displayName, email, photoURL, organizationId, colorCode } = yourAuthenticatedUser; // Create the Velt user object const user = { userId: uid, organizationId: organizationId, // this is the organization id the user belongs to. You should always use this. name: displayName, email: email, photoUrl: photoURL, color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar. textColor: textColor // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present. }; ``` To enable `@mention` in the comments, you need to pass the user's contacts. Learn more about how it works [here](/key-concepts/users/contact-list). Call the `useIdentify()` hook and pass in the Velt `User` object. ```js useIdentify(user); ``` The `useIdentify()` method is asynchronous. You must call `useIdentify` within a child component of the `VeltProvider`, or else it will not work. Provide an initial within the user object. If the initial is not provided in the identify call, then we will automatically create it using the name. The second parameter of the `useIdentify()` method is an optional configuration object that has a `JWT Token` as a field. This can be used to add an additional layer of security to prevent user impersonation. ```js useIdentify(user, { authToken: authToken, }); ``` See [JWT Tokens](/security/jwt-tokens) for more information on how to generate a `JWT Token` with the Velt SDK. `Default: false` By default when you identify a **User**, we maintain the user auth in the browser unless you explicitly sign out the logged in user. If you are changing a User's access or any metadata and want those changes to be reflected immediately, then you should re-call the `identify` method with `forceReset` option set to `true`. ```js useIdentify(user, { forceReset: true }); ``` We recommend following the setup guide that uses `React / Next.js with Hooks` for a cleaner experience. It is critical that you do the following steps within a child component and not within the same root component where you placed the VeltProvider. Realistically, these steps should be done inside your component that handles authentication. Import the `useVeltClient` React hook. You can use this hook within your component to fetch the Velt client. ```js import { useVeltClient } from '@veltdev/react'; ``` ```js const { client } = useVeltClient(); ``` The code in the following steps will go inside this `useEffect` hook. ```js useEffect(() => { if (client && yourAuthenticatedUser) { // Fetch the relevant user info from your authenticated user object. } }, [client, yourAuthenticatedUser]); ``` Create a Velt `User` object by taking the relevant fields from `yourAuthenticatedUser`. ```js // Fetch the relevant user info from `yourAuthenticatedUser` const { uid, displayName, email, photoURL, organizationId, colorCode } = yourAuthenticatedUser; // Create the Velt user object const user = { userId: uid, organizationId: organizationId, // this is the organization id the user belongs to. You should always use this. name: displayName, email: email, photoUrl: photoURL, color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar. textColor: textColor // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present. }; ``` To enable `@mention` in the comments, you need to pass the user's contacts. Learn more about how it works [here](/key-concepts/users/contact-list). Call the `identify()` method and pass in the Velt `User` object. ```js await client.identify(user); ``` The `client.identify()` method is asynchronous. You must call `client.identify` within a child component of the `VeltProvider`, or else it will not work. Provide an initial within the user object. If the initial is not provided in the identify call, then we will automatically create it using the name. The second parameter of the `client.identify()` method is an optional configuration object that has a `JWT Token` as a field. This can be used to add an additional layer of security to prevent user impersonation. ```js await client.identify(user, { authToken: authToken, }); ``` We will use the `email` address and `organizationId` passed in the identify call to validate the user later to prevent unauthorized access. See [JWT Tokens](/security/jwt-tokens) for more information on how to generate a `JWT Token` with the Velt SDK. `Default: false` By default when you identify a **User**, we maintain the user auth in the browser unless you explicitly sign out the logged in user. If you are changing a User's access or any metadata and want those changes to be reflected immediately, then you should re-call the `identify` method with `forceReset` option set to `true`. ```js await client.identify(user, { forceReset: true }); ``` Create a Velt `User` object. ```js // Fetch the relevant user info from `yourAuthenticatedUser` const { uid, displayName, email, photoURL, organizationId, colorCode } = yourAuthenticatedUser; // Create the Velt user object const user = { userId: uid, organizationId: organizationId, // this is the organization id the user belongs to. You should always use this. name: displayName, email: email, photoUrl: photoURL, color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar. textColor: textColor // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present. }; ``` To enable `@mention` in the comments, you need to pass the user's contacts. Learn more about how it works [here](/key-concepts/users/contact-list). Call this function in the component where you authenticate your `Users` once your Velt client and your `User` object is available. If your `.js` files are all in one file, you will need to include the `.js` file on every html page you want the features to be enabled on. Make sure you pass the `User` with the fields defined in the `User` object or refer to the example below. ```js await Velt.identify(yourLoggedInUser) ``` The `Velt.identify()` method is asynchronous You must call `client.identify` within a child component of the `VeltProvider`, or else it will not work. Provide an initial within the user object. If the initial is not provided in the identify call, then we will automatically create it using the name. The second parameter of the `client.identify()` method is an optional configuration object that has a `JWT Token` as a field. This can be used to add an additional layer of security to prevent user impersonation. ```js await Velt.identify(user, { authToken: authToken, }); ``` See [JWT Tokens](/security/jwt-tokens) for more information on how to generate a `JWT Token` with the Velt SDK. `Default: false` By default when you identify a **User**, we maintain the user auth in the browser unless you explicitly sign out the logged in user. If you are changing a User's access or any metadata and want those changes to be reflected immediately, then you should re-call the `identify` method with `forceReset` option set to `true`. ```js await Velt.identify(user, { forceReset: true }); ``` It is critical that you do the following steps within a child component and not within the same root component where you placed the VeltProvider. Realistically, these steps should be done inside your component that handles authentication. Create a Velt User object. ```jsx // Fetch the relevant user info from `yourAuthenticatedUser` const { uid, displayName, email, photoURL, organizationId, colorCode } = yourAuthenticatedUser; // Create the Velt user object const user = { userId: uid, organizationId: organizationId, // this is the organization id the user belongs to. You should always use this. name: displayName, email: email, photoUrl: photoURL, color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar. textColor: textColor // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present. }; ``` ```jsx this.client.identify(user); ``` The `this.client.identify()` method is asynchronous. Provide an initial within the user object. If the initial is not provided in the identify call, then we will automatically create it using the name. The second parameter of the `useIdentify()` method is an optional configuration object that has a `JWT Token` as a field. This can be used to add an additional layer of security to prevent user impersonation. ```js this.client.identify(user, { authToken: authToken, }); ``` See [JWT Tokens](/security/jwt-tokens) for more information on how to generate a `JWT Token` with the Velt SDK. `Default: false` By default when you identify a **User**, we maintain the user auth in the browser unless you explicitly sign out the logged in user. If you are changing a User's access or any metadata and want those changes to be reflected immediately, then you should re-call the `identify` method with `forceReset` option set to `true`. ```js this.client.identify(user, { forceReset: true }); ``` It is critical that you do the following steps within a child component and not within the same root component where you placed the VeltProvider. Realistically, these steps should be done inside your component that handles authentication. Create a Velt User object. ```jsx // Fetch the relevant user info from `yourAuthenticatedUser` const { uid, displayName, email, photoURL, organizationId, colorCode } = yourAuthenticatedUser; // Create the Velt user object const user = { userId: uid, organizationId: organizationId, // this is the organization id the user belongs to. You should always use this. name: displayName, email: email, photoUrl: photoURL, color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar. textColor: textColor // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present. }; ``` ```jsx client.identify(user); ``` The `client.identify()` method is asynchronous. You must call `client.identify()` within a child component of the `VeltProvider`, or else it will not work. Provide an initial within the user object. If the initial is not provided in the identify call, then we will automatically create it using the name. The second parameter of the `useIdentify()` method is an optional configuration object that has a `JWT Token` as a field. This can be used to add an additional layer of security to prevent user impersonation. ```js client.identify(user, { authToken: authToken, }); ``` See [JWT Tokens](/security/jwt-tokens) for more information on how to generate a `JWT Token` with the Velt SDK. `Default: false` By default when you identify a **User**, we maintain the user auth in the browser unless you explicitly sign out the logged in user. If you are changing a User's access or any metadata and want those changes to be reflected immediately, then you should re-call the `identify` method with `forceReset` option set to `true`. ```js client.identify(user, { forceReset: true }); ``` ```js React / Next.js with Hooks //Warning: Make sure this is a child component to VeltProvider //and not within the same file where VeltProvider is placed. // 1) Import the useIdentify hook import { useIdentify } from '@veltdev/react'; export default function YourAuthComponent() { const userService = () => { return { uid:"123", organizationId: "organizationId123", // this is the organization id the user belongs to. You should always use this. displayName:"Bob", email:"bob@gmail.com", photoURL:'https://i.pravatar.cc/300', color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar. textColor: textColor // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present. } } let yourAuthenticatedUser = userService() // 2) Fetch the relevant User info from yourAuthenticatedUser const { uid, displayName, email, photoURL, organizationId, colorCode } = yourAuthenticatedUser; // Create the Velt user object const user = { userId: uid, organizationId: organizationId, // this is the organization id the user belongs to. You should always use this. name: displayName, email: email, photoUrl: photoURL, color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar. textColor: textColor // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present. }; //3) Pass the user object to the SDK useIdentify(user) return (
// Your auth component template
); } ``` ```js React / Next.js //Warning: Make sure this is a child component to VeltProvider //and not within the same file where VeltProvider is placed. // 1) Get the Velt Client import { useVeltClient } from '@veltdev/react'; import { useEffect } from 'react'; export default function YourAuthComponent() { const userService = () => { return { uid:"123", organizationId: "organizationId123", // this is the organization id the user belongs to. You should always use this. displayName:"Bob", email:"bob@gmail.com", photoURL:'https://i.pravatar.cc/300', color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar. textColor: textColor // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present. } } let yourAuthenticatedUser = userService() const { client } = useVeltClient(); // 2) Create a useEffect hook useEffect(() => { const initVelt = async () => { if (client && yourAuthenticatedUser) { // 3) Fetch the relevant user info from yourAuthenticatedUser const { uid, displayName, email, photoURL, organizationId, colorCode } = yourAuthenticatedUser; // Create the Velt user object const user = { userId: uid, organizationId: organizationId, // this is the organization id the user belongs to. You should always use this. name: displayName, email: email, photoUrl: photoURL, color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar. textColor: textColor, // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present. }; //4) Pass the user object to the SDK await client.identify(user) } } initVelt().catch(console.error) }, [client, yourAuthenticatedUser]); return (
// Your auth component template
); } ``` ```html HTML Collaboration App ``` ```jsx Angular import { Component } from '@angular/core'; import { initVelt } from '@veltdev/client'; import { Velt } from '@veltdev/types'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { client?: Velt; constructor() { this.initVelt(); } // Initialize velt sdk async initVelt() { this.client = await initVelt('YOUR_APIKEY'); this.setUser(); } // login with your user in velt setUser() { if (this.client) { const user = { userId: uid, organizationId: 'organizationId123', // this is the organization id the user belongs to. You should always use this. name: displayName, email: email, photoUrl: photoURL, color: colorCode, // Use valid Hex code value. Used in the background color of the user's avatar. textColor: textColor // Use valid Hex code value. Used in the text color of the user's intial when photoUrl is not present. }; // Your user object here this.client.identify(user); } } } ``` ```html Vue.js ```
# 3. Initialize Document Source: https://docs.velt.dev/get-started/setup/initialize-document A **Document** represents a shared collaborative space where users can interact. Documents live inside the Organization. Learn more about documents [here](/key-concepts/documents). The Set Document method takes two parameters: * `documentId`: The unique identifier for the document. * `metadata`: (optional) This is a key/value pair object where you can set metadata about the document such as `documentName`. documentName is a special field that we use to display the document name in some Velt Components. The SDK will not work without this call. ## 1. Initialize Document for the current Organization * By default, users can only access documents within their own organization. Use this to set the document for the current organization the user is logged into. It is critical that you do the following steps within a child component and not within the same root component where you placed the VeltProvider. Realistically, these steps should be done inside your component that represents your document. ```jsx import { useSetDocument } from '@veltdev/react'; useSetDocument('unique-document-id', {documentName: 'Document Name'}); ``` It is critical that you do the following steps within a child component and not within the same root component where you placed the VeltProvider. Realistically, these steps should be done inside your component that represents your document. ```jsx const { client } = useVeltClient(); useEffect(() => { if (client) { client.setDocument('unique-document-id', {documentName: 'Document Name'}); } }, [client]); ``` ```jsx if(Velt){ Velt.setDocument('unique-document-id', {documentName: 'Document Name'}); } ``` ```jsx if (this.client) { this.client.setDocument('unique-document-id', {documentName: 'Document Name'}); } ``` ```jsx if (client) { client.setDocument('unique-document-id', {documentName: 'Document Name'}); } ``` ## 2. Initialize Document for a different Organization * Use this to access a document from an organization different than the one the user is logged into. * You can enable cross-organization access by specifying the `organizationId` of the target document in the document metadata. * Ensure that the user has access to the target document in the target organization. It is critical that you do the following steps within a child component and not within the same root component where you placed the VeltProvider. Realistically, these steps should be done inside your component that represents your document. ```jsx import { useSetDocument } from '@veltdev/react'; useSetDocument('unique-document-id', {organizationId: 'ANOTHER_ORGANIZATION_ID'}); ``` It is critical that you do the following steps within a child component and not within the same root component where you placed the VeltProvider. Realistically, these steps should be done inside your component that represents your document. ```jsx const { client } = useVeltClient(); useEffect(() => { if (client) { client.setDocument('unique-document-id', {organizationId: 'ANOTHER_ORGANIZATION_ID'}); } }, [client]); ``` ```jsx if(Velt){ Velt.setDocument('unique-document-id', {organizationId: 'ANOTHER_ORGANIZATION_ID'}); } ``` ```jsx if (this.client) { this.client.setDocument('unique-document-id', {organizationId: 'ANOTHER_ORGANIZATION_ID'}); } ``` ```jsx if (client) { client.setDocument('unique-document-id', {organizationId: 'ANOTHER_ORGANIZATION_ID'}); } ``` ```js React / Next.js with Hooks // 1) Create a component that will represent your document //Warning: Make sure this is a child component to VeltProvider //and not within the same file where VeltProvider is placed. // 2) Import the useSetDocument hook import { useSetDocument } from '@veltdev/react'; export default function YourDocument() { // 3) Set a document ID useSetDocument('unique-document-id', {documentName: 'Document Name'}); return (
//your document template - add Velt Components here
); } ``` ```js React / Next.js // 1) Create a component that will represent your document //Warning: Make sure this is a child component to VeltProvider //and not within the same file where VeltProvider is placed. // 2) Get the Velt client import { useVeltClient } from '@veltdev/react'; import { useEffect, useState } from 'react'; export default function YourDocument() { const { client } = useVeltClient(); // 3) Create a useEffect hook useEffect(() => { if (client) { // 4) Set a document ID client.setDocument('unique-document-id', {documentName: 'Document Name'}); } }, [client]); return (
//your document template - add Velt Components here
); } ``` ```html HTML Collaboration App //your document template - add Velt Components here ``` ```jsx Angular import { Component } from '@angular/core'; import { initVelt } from '@veltdev/client'; import { Velt } from '@veltdev/types'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { client?: Velt; constructor() { this.initVelt(); } // Initialize velt sdk async initVelt() { this.client = await initVelt('YOUR_APIKEY'); this.setDocument(); } // set document in velt setDocument() { if (this.client) { this.client.setDocument('YOUR_DOCUMENT_ID', {documentName: 'Document Name'}); } } } // Your HTML File //
// to add comments (ideally add to root component ex: AppComponent) // comment tool // comment sidebar // Add other feature tags ...
``` ```html Vue.js ```
# 1. Install Source: https://docs.velt.dev/get-started/setup/install Steps to integrate Velt into an existing app npm: ```bash npm install @veltdev/react ``` yarn: ```bash $ yarn add @veltdev/react ``` If you're using TypeScript, you can install the types package. ```bash npm install --save-dev @veltdev/types ``` Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/velt-console-api-key.png) In the Velt console, add the URL where your app is deployed to the list of Managed Domains. ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/velt-console-add-website.png) Add the VeltProvider component to the root of your app. Add your Velt API key. ```js import { VeltProvider } from '@veltdev/react'; ``` ```js ``` ```js 'use client' import { VeltProvider } from '@veltdev/react'; ``` We recommend following the setup guide that uses `React / Next.js with Hooks` for a cleaner experience. npm: ```bash npm install @veltdev/react ``` yarn: ```bash $ yarn add @veltdev/react ``` If you're using TypeScript, you can install the types package. ```bash npm install --save-dev @veltdev/types ``` Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/velt-console-api-key.png) In the Velt console, add the URL where your app is deployed to the list of Managed Domains. ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/velt-console-add-website.png) Add the VeltProvider component to the root of your app. Add your Velt API key. ```js import { VeltProvider } from '@veltdev/react'; ``` ```js ``` ```js 'use client' import { VeltProvider } from '@veltdev/react'; ``` Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/velt-console-api-key.png) In the Velt console, add the URL where your app is deployed to the list of Managed Domains. ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/velt-console-add-website.png) ```html ``` Put this in your root app script: ```js async function loadVelt() { await Velt.init("YOUR_VELT_API_KEY"); } ``` ```jsx npm i @veltdev/client ``` If you are using Typescript, install the types library: ```jsx npm i @veltdev/types --save-dev ``` Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/velt-console-api-key.png) In the Velt console, add the URL where your app is deployed to the list of Managed Domains. ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/velt-console-add-website.png) Add `schemas: [CUSTOM_ELEMENTS_SCHEMA]` to your App Module: ```jsx import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], // Add this line }) export class AppModule { } ``` ```jsx import { initVelt } from '@veltdev/client'; ``` ```jsx this.client = await initVelt('YOUR_APIKEY'); ``` ```jsx npm i @veltdev/client ``` If you are using Typescript, install the types library: ```jsx npm i @veltdev/types --save-dev ``` Go to [console.velt.dev](https://console.velt.dev) and grab your Velt API Key ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/velt-console-api-key.png) In the Velt console, add the URL where your app is deployed to the list of Managed Domains. ![](https://mintlify.s3.us-west-1.amazonaws.com/velt/images/velt-console-add-website.png) In main.js, add the following code to allow Velt elements in your Vue app: ```html Vue.config.ignoredElements = [ /velt-*/ ] ``` ```jsx import { initVelt } from '@veltdev/client'; ``` ```jsx client = await initVelt("YOUR_APIKEY"); ``` ```jsx React / Next.js with Hooks 'use client' // Add this line for Next.js only import { VeltProvider } from '@veltdev/react'; export default function App() { return ( ); } ``` ```jsx React / Next.js 'use client' // Add this line for Next.js only import { VeltProvider } from '@veltdev/react'; export default function App() { return ( ); } ``` ```html HTML Collaboration App ``` ```jsx Angular import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], // Add this line }) export class AppModule { } // App Component import { initVelt } from '@veltdev/client'; @Component({ selector: 'app-root', }) export class AppComponent implements OnInit { client: any; async ngOnInit() { this.client = await initVelt('YOUR_APIKEY'); } } ``` ```js Vue.js // main.js Vue.config.ignoredElements = [ /velt-*/ ] // App.vue import { initVelt } from '@veltdev/client'; export default { name: 'App', async mounted() { client = await initVelt('YOUR_APIKEY'); } } ``` # CSS Injection Source: https://docs.velt.dev/global-styles/css-injection ## Custom CSS Injection You can inject CSS with our special `client.injectCustomCss()` method. ### Passing style definition via string ```jsx client?.injectCustomCss({ type: 'styles', value: ` .modal-div.dialog .modal-author__name { font-size: 10rem !important; background-color: green !important; color: white !important; } ` }); ``` ### Passing style via link. ```jsx client?.injectCustomCss({ type: 'link', value: '/relative_path_to_css/styles.css' // you could also pass the absolute link: 'https://yourappdomain.com/pathtocss/styles.css' }); ``` ## Custom CSS Injection You can inject CSS with our special `client.injectCustomCss()` method. ### Passing style definition via string ```jsx Velt?.injectCustomCss({ type: 'styles', value: ` .modal-div.dialog .modal-author__name { font-size: 10rem !important; background-color: green !important; color: white !important; } ` }); ``` ### Passing style via link. ```jsx Velt?.injectCustomCss({ type: 'link', value: '/relative_path_to_css/styles.css' // you could also pass the absolute link: 'https://yourappdomain.com/pathtocss/styles.css' }); ``` ```jsx React / Next.js import { useVeltClient } from '@veltdev/react'; import { useEffect, useState } from 'react'; export default function YourDocument() { const { client } = useVeltClient(); useEffect(() => { if (client) { client?.injectCustomCss({ type: 'styles', value: ` .modal-div.dialog .modal-author__name { font-size: 10rem !important; background-color: green !important; color: white !important; } ` }); client?.injectCustomCss({ type: 'link', value: '/relative_path_to_css/styles.css' // you could also pass the absolute link: 'https://yourappdomain.com/pathtocss/styles.css' }); } }, [client]); return (
//your document template
); } ``` ```html HTML ```
# Dark Mode Source: https://docs.velt.dev/global-styles/dark-mode ## Enable Dark Mode on all Components To enable Dark Mode on all Components, call the `client.setDarkMode(true)` ```jsx let client = useVeltClient(); client.setDarkMode(true); ``` ## Enable Dark Mode on individual Components To enable Dark Mode on individual components, set the `darkMode` attribute to `true`. ```jsx ``` API Methods: ```jsx commentElement.enableDarkMode() commentElement.disableDarkMode() ``` ## Enable Dark Mode on all Components To enable Dark Mode on all Components, call the `Velt.setDarkMode(true)` ```jsx Velt.setDarkMode(true); ``` ## Enable Dark Mode on individual Components To enable Dark Mode on individual components, set the `dark-mode` attribute to `true`. ```jsx ``` API Methods: ```jsx commentElement.enableDarkMode() commentElement.disableDarkMode() ``` # Global Styles Source: https://docs.velt.dev/global-styles/global-styles To edit the styling for all Velt components, you can use the following global CSS variables. This is recommended over editing the CSS for each tool individually. ```scss // default state --velt-tool-padding: 6px; --velt-tool-icon-size: 1.5rem; --velt-tool-icon-color: var(--velt-neutral-4); --velt-tool-border-radius: 50px; --velt-tool-border-color: transparent; --velt-tool-border: 2px solid var(--velt-tool-border-color); --velt-tool-bg-color: transparent; // default focus state --velt-tool-focus-icon-size: var(--velt-tool-icon-size); --velt-tool-focus-icon-color: var(--velt-tool-icon-color); --velt-tool-focus-border-radius: var(--velt-tool-border-radius); --velt-tool-focus-border-color: var(--velt-neutral-7); --velt-tool-focus-border: 2px solid var(--velt-tool-focus-border-color); --velt-tool-focus-bg-color: var(--velt-tool-bg-color); // default hover state --velt-tool-hover-icon-size: var(--velt-tool-icon-size); --velt-tool-hover-icon-color: var(--velt-neutral-3); --velt-tool-hover-border-radius: var(--velt-tool-border-radius); --velt-tool-hover-border-color: var(--velt-neutral-7); --velt-tool-hover-border: 2px solid var(--velt-tool-hover-border-color); --velt-tool-hover-bg-color: var(--velt-neutral-7); // active state --velt-tool-active-icon-size: var(--velt-tool-icon-size); --velt-tool-active-icon-color: var(--velt-neutral-9); --velt-tool-active-border-radius: var(--velt-tool-border-radius); --velt-tool-active-border-color: var(--velt-purple); --velt-tool-active-border: 2px solid var(--velt-tool-active-border-color); --velt-tool-active-bg-color: var(--velt-purple); // active focus state --velt-tool-active-focus-icon-size: var(--velt-tool-icon-size); --velt-tool-active-focus-icon-color: var(--velt-tool-icon-color); --velt-tool-active-focus-border-radius: var(--velt-tool-border-radius); --velt-tool-active-focus-border-color: rgba(255, 255, 255, 0.24); --velt-tool-active-focus-border: 2px solid var(--velt-tool-active-focus-border-color); --velt-tool-active-focus-bg-color: var(--velt-purple); // active hover state --velt-tool-active-hover-icon-size: var(--velt-tool-icon-size); --velt-tool-active-hover-icon-color: var(--velt-tool-icon-color); --velt-tool-active-hover-border-radius: var(--velt-tool-border-radius); --velt-tool-active-hover-border-color: #433fa7; --velt-tool-active-hover-border: 2px solid var(--velt-tool-active-hover-border-color); --velt-tool-active-hover-bg-color: #433fa7; ``` ```scss Styles.css // default state --velt-tool-padding: 6px; --velt-tool-icon-size: 1.5rem; --velt-tool-icon-color: var(--velt-neutral-4); --velt-tool-border-radius: 50px; --velt-tool-border-color: transparent; --velt-tool-border: 2px solid var(--velt-tool-border-color); --velt-tool-bg-color: transparent; // default focus state --velt-tool-focus-icon-size: var(--velt-tool-icon-size); --velt-tool-focus-icon-color: var(--velt-tool-icon-color); --velt-tool-focus-border-radius: var(--velt-tool-border-radius); --velt-tool-focus-border-color: var(--velt-neutral-7); --velt-tool-focus-border: 2px solid var(--velt-tool-focus-border-color); --velt-tool-focus-bg-color: var(--velt-tool-bg-color); // default hover state --velt-tool-hover-icon-size: var(--velt-tool-icon-size); --velt-tool-hover-icon-color: var(--velt-neutral-3); --velt-tool-hover-border-radius: var(--velt-tool-border-radius); --velt-tool-hover-border-color: var(--velt-neutral-7); --velt-tool-hover-border: 2px solid var(--velt-tool-hover-border-color); --velt-tool-hover-bg-color: var(--velt-neutral-7); // active state --velt-tool-active-icon-size: var(--velt-tool-icon-size); --velt-tool-active-icon-color: var(--velt-neutral-9); --velt-tool-active-border-radius: var(--velt-tool-border-radius); --velt-tool-active-border-color: var(--velt-purple); --velt-tool-active-border: 2px solid var(--velt-tool-active-border-color); --velt-tool-active-bg-color: var(--velt-purple); // active focus state --velt-tool-active-focus-icon-size: var(--velt-tool-icon-size); --velt-tool-active-focus-icon-color: var(--velt-tool-icon-color); --velt-tool-active-focus-border-radius: var(--velt-tool-border-radius); --velt-tool-active-focus-border-color: rgba(255, 255, 255, 0.24); --velt-tool-active-focus-border: 2px solid var(--velt-tool-active-focus-border-color); --velt-tool-active-focus-bg-color: var(--velt-purple); // active hover state --velt-tool-active-hover-icon-size: var(--velt-tool-icon-size); --velt-tool-active-hover-icon-color: var(--velt-tool-icon-color); --velt-tool-active-hover-border-radius: var(--velt-tool-border-radius); --velt-tool-active-hover-border-color: #433fa7; --velt-tool-active-hover-border: 2px solid var(--velt-tool-active-hover-border-color); --velt-tool-active-hover-bg-color: #433fa7; ``` # Customize Behavior Source: https://docs.velt.dev/in-app-user-feedback/customize-behavior ## 1. Feedback Mode By default the component will be in `Feedback` mode. This will make your component say *"Give feedback"* and have a heart icon. ```js ```